Doxygen_Hew2023
Loading...
Searching...
No Matches
imgui.cpp
Go to the documentation of this file.
1// dear imgui, v1.89.4 WIP
2// (main code and documentation)
3
4// Help:
5// - Read FAQ at http://dearimgui.org/faq
6// - Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImGui in your codebase.
7// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that.
8// Read imgui.cpp for details, links and comments.
9
10// Resources:
11// - FAQ http://dearimgui.org/faq
12// - Homepage & latest https://github.com/ocornut/imgui
13// - Releases & changelog https://github.com/ocornut/imgui/releases
14// - Gallery https://github.com/ocornut/imgui/issues/5886 (please post your screenshots/video there!)
15// - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there)
16// - Glossary https://github.com/ocornut/imgui/wiki/Glossary
17// - Issues & support https://github.com/ocornut/imgui/issues
18
19// Getting Started?
20// - For first-time users having issues compiling/linking/running or issues loading fonts:
21// please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above.
22
23// Developed by Omar Cornut and every direct or indirect contributors to the GitHub.
24// See LICENSE.txt for copyright and licensing details (standard MIT License).
25// This library is free but needs your support to sustain development and maintenance.
26// Businesses: you can support continued development via invoiced technical support, maintenance and sponsoring contracts. Please reach out to "contact AT dearimgui.com".
27// Individuals: you can support continued development via donations. See docs/README or web page.
28
29// It is recommended that you don't modify imgui.cpp! It will become difficult for you to update the library.
30// Note that 'ImGui::' being a namespace, you can add functions into the namespace from your own source files, without
31// modifying imgui.h or imgui.cpp. You may include imgui_internal.h to access internal data structures, but it doesn't
32// come with any guarantee of forward compatibility. Discussing your changes on the GitHub Issue Tracker may lead you
33// to a better solution or official support for them.
34
35/*
36
37Index of this file:
38
39DOCUMENTATION
40
41- MISSION STATEMENT
42- CONTROLS GUIDE
43- PROGRAMMER GUIDE
44 - READ FIRST
45 - HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI
46 - GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE
47 - HOW A SIMPLE APPLICATION MAY LOOK LIKE
48 - HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE
49- API BREAKING CHANGES (read me when you update!)
50- FREQUENTLY ASKED QUESTIONS (FAQ)
51 - Read all answers online: https://www.dearimgui.org/faq, or in docs/FAQ.md (with a Markdown viewer)
52
53CODE
54(search for "[SECTION]" in the code to find them)
55
56// [SECTION] INCLUDES
57// [SECTION] FORWARD DECLARATIONS
58// [SECTION] CONTEXT AND MEMORY ALLOCATORS
59// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO)
60// [SECTION] MISC HELPERS/UTILITIES (Geometry functions)
61// [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions)
62// [SECTION] MISC HELPERS/UTILITIES (File functions)
63// [SECTION] MISC HELPERS/UTILITIES (ImText* functions)
64// [SECTION] MISC HELPERS/UTILITIES (Color functions)
65// [SECTION] ImGuiStorage
66// [SECTION] ImGuiTextFilter
67// [SECTION] ImGuiTextBuffer, ImGuiTextIndex
68// [SECTION] ImGuiListClipper
69// [SECTION] STYLING
70// [SECTION] RENDER HELPERS
71// [SECTION] INITIALIZATION, SHUTDOWN
72// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
73// [SECTION] INPUTS
74// [SECTION] ERROR CHECKING
75// [SECTION] LAYOUT
76// [SECTION] SCROLLING
77// [SECTION] TOOLTIPS
78// [SECTION] POPUPS
79// [SECTION] KEYBOARD/GAMEPAD NAVIGATION
80// [SECTION] DRAG AND DROP
81// [SECTION] LOGGING/CAPTURING
82// [SECTION] SETTINGS
83// [SECTION] LOCALIZATION
84// [SECTION] VIEWPORTS, PLATFORM WINDOWS
85// [SECTION] PLATFORM DEPENDENT HELPERS
86// [SECTION] METRICS/DEBUGGER WINDOW
87// [SECTION] DEBUG LOG WINDOW
88// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, STACK TOOL)
89
90*/
91
92//-----------------------------------------------------------------------------
93// DOCUMENTATION
94//-----------------------------------------------------------------------------
95
96/*
97
98 MISSION STATEMENT
99 =================
100
101 - Easy to use to create code-driven and data-driven tools.
102 - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools.
103 - Easy to hack and improve.
104 - Minimize setup and maintenance.
105 - Minimize state storage on user side.
106 - Minimize state synchronization.
107 - Portable, minimize dependencies, run on target (consoles, phones, etc.).
108 - Efficient runtime and memory consumption.
109
110 Designed for developers and content-creators, not the typical end-user! Some of the current weaknesses includes:
111
112 - Doesn't look fancy, doesn't animate.
113 - Limited layout features, intricate layouts are typically crafted in code.
114
115
116 CONTROLS GUIDE
117 ==============
118
119 - MOUSE CONTROLS
120 - Mouse wheel: Scroll vertically.
121 - SHIFT+Mouse wheel: Scroll horizontally.
122 - Click [X]: Close a window, available when 'bool* p_open' is passed to ImGui::Begin().
123 - Click ^, Double-Click title: Collapse window.
124 - Drag on corner/border: Resize window (double-click to auto fit window to its contents).
125 - Drag on any empty space: Move window (unless io.ConfigWindowsMoveFromTitleBarOnly = true).
126 - Left-click outside popup: Close popup stack (right-click over underlying popup: Partially close popup stack).
127
128 - TEXT EDITOR
129 - Hold SHIFT or Drag Mouse: Select text.
130 - CTRL+Left/Right: Word jump.
131 - CTRL+Shift+Left/Right: Select words.
132 - CTRL+A or Double-Click: Select All.
133 - CTRL+X, CTRL+C, CTRL+V: Use OS clipboard.
134 - CTRL+Z, CTRL+Y: Undo, Redo.
135 - ESCAPE: Revert text to its original value.
136 - On OSX, controls are automatically adjusted to match standard OSX text editing shortcuts and behaviors.
137
138 - KEYBOARD CONTROLS
139 - Basic:
140 - Tab, SHIFT+Tab Cycle through text editable fields.
141 - CTRL+Tab, CTRL+Shift+Tab Cycle through windows.
142 - CTRL+Click Input text into a Slider or Drag widget.
143 - Extended features with `io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard`:
144 - Tab, SHIFT+Tab: Cycle through every items.
145 - Arrow keys Move through items using directional navigation. Tweak value.
146 - Arrow keys + Alt, Shift Tweak slower, tweak faster (when using arrow keys).
147 - Enter Activate item (prefer text input when possible).
148 - Space Activate item (prefer tweaking with arrows when possible).
149 - Escape Deactivate item, leave child window, close popup.
150 - Page Up, Page Down Previous page, next page.
151 - Home, End Scroll to top, scroll to bottom.
152 - Alt Toggle between scrolling layer and menu layer.
153 - CTRL+Tab then Ctrl+Arrows Move window. Hold SHIFT to resize instead of moving.
154 - Output when ImGuiConfigFlags_NavEnableKeyboard set,
155 - io.WantCaptureKeyboard flag is set when keyboard is claimed.
156 - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set.
157 - io.NavVisible: true when the navigation cursor is visible (usually goes to back false when mouse is used).
158
159 - GAMEPAD CONTROLS
160 - Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
161 - Particularly useful to use Dear ImGui on a console system (e.g. PlayStation, Switch, Xbox) without a mouse!
162 - Download controller mapping PNG/PSD at http://dearimgui.org/controls_sheets
163 - Backend support: backend needs to:
164 - Set 'io.BackendFlags |= ImGuiBackendFlags_HasGamepad' + call io.AddKeyEvent/AddKeyAnalogEvent() with ImGuiKey_Gamepad_XXX keys.
165 - For analog values (0.0f to 1.0f), backend is responsible to handling a dead-zone and rescaling inputs accordingly.
166 Backend code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.).
167 - BEFORE 1.87, BACKENDS USED TO WRITE TO io.NavInputs[]. This is now obsolete. Please call io functions instead!
168 - If you need to share inputs between your game and the Dear ImGui interface, the easiest approach is to go all-or-nothing,
169 with a buttons combo to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved.
170
171 - REMOTE INPUTS SHARING & MOUSE EMULATION
172 - PS4/PS5 users: Consider emulating a mouse cursor with DualShock touch pad or a spare analog stick as a mouse-emulation fallback.
173 - Consoles/Tablet/Phone users: Consider using a Synergy 1.x server (on your PC) + run examples/libs/synergy/uSynergy.c (on your console/tablet/phone app)
174 in order to share your PC mouse/keyboard.
175 - See https://github.com/ocornut/imgui/wiki/Useful-Extensions#remoting for other remoting solutions.
176 - On a TV/console system where readability may be lower or mouse inputs may be awkward, you may want to set the ImGuiConfigFlags_NavEnableSetMousePos flag.
177 Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs Dear ImGui to move your mouse cursor along with navigation movements.
178 When enabled, the NewFrame() function may alter 'io.MousePos' and set 'io.WantSetMousePos' to notify you that it wants the mouse cursor to be moved.
179 When that happens your backend NEEDS to move the OS or underlying mouse cursor on the next frame. Some of the backends in examples/ do that.
180 (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMousePos' properly, Dear ImGui will misbehave as it will see your mouse moving back & forth!)
181 (In a setup when you may not have easy control over the mouse cursor, e.g. uSynergy.c doesn't expose moving remote mouse cursor, you may want
182 to set a boolean to ignore your other external mouse positions until the external source is moved again.)
183
184
185 PROGRAMMER GUIDE
186 ================
187
188 READ FIRST
189 ----------
190 - Remember to check the wonderful Wiki (https://github.com/ocornut/imgui/wiki)
191 - Your code creates the UI, if your code doesn't run the UI is gone! The UI can be highly dynamic, there are no construction or
192 destruction steps, less superfluous data retention on your side, less state duplication, less state synchronization, fewer bugs.
193 - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features.
194 - The library is designed to be built from sources. Avoid pre-compiled binaries and packaged versions. See imconfig.h to configure your build.
195 - Dear ImGui is an implementation of the IMGUI paradigm (immediate-mode graphical user interface, a term coined by Casey Muratori).
196 You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links in Wiki.
197 - Dear ImGui is a "single pass" rasterizing implementation of the IMGUI paradigm, aimed at ease of use and high-performances.
198 For every application frame, your UI code will be called only once. This is in contrast to e.g. Unity's implementation of an IMGUI,
199 where the UI code is called multiple times ("multiple passes") from a single entry point. There are pros and cons to both approaches.
200 - Our origin is on the top-left. In axis aligned bounding boxes, Min = top-left, Max = bottom-right.
201 - This codebase is also optimized to yield decent performances with typical "Debug" builds settings.
202 - Please make sure you have asserts enabled (IM_ASSERT redirects to assert() by default, but can be redirected).
203 If you get an assert, read the messages and comments around the assert.
204 - C++: this is a very C-ish codebase: we don't rely on C++11, we don't include any C++ headers, and ImGui:: is a namespace.
205 - C++: ImVec2/ImVec4 do not expose math operators by default, because it is expected that you use your own math types.
206 See FAQ "How can I use my own math types instead of ImVec2/ImVec4?" for details about setting up imconfig.h for that.
207 However, imgui_internal.h can optionally export math operators for ImVec2/ImVec4, which we use in this codebase.
208 - C++: pay attention that ImVector<> manipulates plain-old-data and does not honor construction/destruction (avoid using it in your code!).
209
210
211 HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI
212 ----------------------------------------------
213 - Overwrite all the sources files except for imconfig.h (if you have modified your copy of imconfig.h)
214 - Or maintain your own branch where you have imconfig.h modified as a top-most commit which you can regularly rebase over "master".
215 - You can also use '#define IMGUI_USER_CONFIG "my_config_file.h" to redirect configuration to your own file.
216 - Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes.
217 If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed
218 from the public API. If you have a problem with a missing function/symbols, search for its name in the code, there will
219 likely be a comment about it. Please report any issue to the GitHub page!
220 - To find out usage of old API, you can add '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in your configuration file.
221 - Try to keep your copy of Dear ImGui reasonably up to date.
222
223
224 GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE
225 ---------------------------------------------------------------
226 - Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library.
227 - In the majority of cases you should be able to use unmodified backends files available in the backends/ folder.
228 - Add the Dear ImGui source files + selected backend source files to your projects or using your preferred build system.
229 It is recommended you build and statically link the .cpp files as part of your project and NOT as a shared library (DLL).
230 - You can later customize the imconfig.h file to tweak some compile-time behavior, such as integrating Dear ImGui types with your own maths types.
231 - When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them.
232 - Dear ImGui never touches or knows about your GPU state. The only function that knows about GPU is the draw function that you provide.
233 Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render"
234 phases of your own application. All rendering information is stored into command-lists that you will retrieve after calling ImGui::Render().
235 - Refer to the backends and demo applications in the examples/ folder for instruction on how to setup your code.
236 - If you are running over a standard OS with a common graphics API, you should be able to use unmodified imgui_impl_*** files from the examples/ folder.
237
238
239 HOW A SIMPLE APPLICATION MAY LOOK LIKE
240 --------------------------------------
241 EXHIBIT 1: USING THE EXAMPLE BACKENDS (= imgui_impl_XXX.cpp files from the backends/ folder).
242 The sub-folders in examples/ contain examples applications following this structure.
243
244 // Application init: create a dear imgui context, setup some options, load fonts
245 ImGui::CreateContext();
246 ImGuiIO& io = ImGui::GetIO();
247 // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls.
248 // TODO: Fill optional fields of the io structure later.
249 // TODO: Load TTF/OTF fonts if you don't want to use the default font.
250
251 // Initialize helper Platform and Renderer backends (here we are using imgui_impl_win32.cpp and imgui_impl_dx11.cpp)
252 ImGui_ImplWin32_Init(hwnd);
253 ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);
254
255 // Application main loop
256 while (true)
257 {
258 // Feed inputs to dear imgui, start new frame
259 ImGui_ImplDX11_NewFrame();
260 ImGui_ImplWin32_NewFrame();
261 ImGui::NewFrame();
262
263 // Any application code here
264 ImGui::Text("Hello, world!");
265
266 // Render dear imgui into screen
267 ImGui::Render();
268 ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
269 g_pSwapChain->Present(1, 0);
270 }
271
272 // Shutdown
273 ImGui_ImplDX11_Shutdown();
274 ImGui_ImplWin32_Shutdown();
275 ImGui::DestroyContext();
276
277 EXHIBIT 2: IMPLEMENTING CUSTOM BACKEND / CUSTOM ENGINE
278
279 // Application init: create a dear imgui context, setup some options, load fonts
280 ImGui::CreateContext();
281 ImGuiIO& io = ImGui::GetIO();
282 // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls.
283 // TODO: Fill optional fields of the io structure later.
284 // TODO: Load TTF/OTF fonts if you don't want to use the default font.
285
286 // Build and load the texture atlas into a texture
287 // (In the examples/ app this is usually done within the ImGui_ImplXXX_Init() function from one of the demo Renderer)
288 int width, height;
289 unsigned char* pixels = NULL;
290 io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
291
292 // At this point you've got the texture data and you need to upload that to your graphic system:
293 // After we have created the texture, store its pointer/identifier (_in whichever format your engine uses_) in 'io.Fonts->TexID'.
294 // This will be passed back to your via the renderer. Basically ImTextureID == void*. Read FAQ for details about ImTextureID.
295 MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA32)
296 io.Fonts->SetTexID((void*)texture);
297
298 // Application main loop
299 while (true)
300 {
301 // Setup low-level inputs, e.g. on Win32: calling GetKeyboardState(), or write to those fields from your Windows message handlers, etc.
302 // (In the examples/ app this is usually done within the ImGui_ImplXXX_NewFrame() function from one of the demo Platform Backends)
303 io.DeltaTime = 1.0f/60.0f; // set the time elapsed since the previous frame (in seconds)
304 io.DisplaySize.x = 1920.0f; // set the current display width
305 io.DisplaySize.y = 1280.0f; // set the current display height here
306 io.AddMousePosEvent(mouse_x, mouse_y); // update mouse position
307 io.AddMouseButtonEvent(0, mouse_b[0]); // update mouse button states
308 io.AddMouseButtonEvent(1, mouse_b[1]); // update mouse button states
309
310 // Call NewFrame(), after this point you can use ImGui::* functions anytime
311 // (So you want to try calling NewFrame() as early as you can in your main loop to be able to use Dear ImGui everywhere)
312 ImGui::NewFrame();
313
314 // Most of your application code here
315 ImGui::Text("Hello, world!");
316 MyGameUpdate(); // may use any Dear ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End();
317 MyGameRender(); // may use any Dear ImGui functions as well!
318
319 // Render dear imgui, swap buffers
320 // (You want to try calling EndFrame/Render as late as you can, to be able to use Dear ImGui in your own game rendering code)
321 ImGui::EndFrame();
322 ImGui::Render();
323 ImDrawData* draw_data = ImGui::GetDrawData();
324 MyImGuiRenderFunction(draw_data);
325 SwapBuffers();
326 }
327
328 // Shutdown
329 ImGui::DestroyContext();
330
331 To decide whether to dispatch mouse/keyboard inputs to Dear ImGui to the rest of your application,
332 you should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags!
333 Please read the FAQ and example applications for details about this!
334
335
336 HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE
337 ---------------------------------------------
338 The backends in impl_impl_XXX.cpp files contain many working implementations of a rendering function.
339
340 void MyImGuiRenderFunction(ImDrawData* draw_data)
341 {
342 // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled
343 // TODO: Setup texture sampling state: sample with bilinear filtering (NOT point/nearest filtering). Use 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines;' to allow point/nearest filtering.
344 // TODO: Setup viewport covering draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize
345 // TODO: Setup orthographic projection matrix cover draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize
346 // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color.
347 ImVec2 clip_off = draw_data->DisplayPos;
348 for (int n = 0; n < draw_data->CmdListsCount; n++)
349 {
350 const ImDrawList* cmd_list = draw_data->CmdLists[n];
351 const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by Dear ImGui
352 const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by Dear ImGui
353 for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
354 {
355 const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
356 if (pcmd->UserCallback)
357 {
358 pcmd->UserCallback(cmd_list, pcmd);
359 }
360 else
361 {
362 // Project scissor/clipping rectangles into framebuffer space
363 ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
364 ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
365 if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
366 continue;
367
368 // We are using scissoring to clip some objects. All low-level graphics API should support it.
369 // - If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches
370 // (some elements visible outside their bounds) but you can fix that once everything else works!
371 // - Clipping coordinates are provided in imgui coordinates space:
372 // - For a given viewport, draw_data->DisplayPos == viewport->Pos and draw_data->DisplaySize == viewport->Size
373 // - In a single viewport application, draw_data->DisplayPos == (0,0) and draw_data->DisplaySize == io.DisplaySize, but always use GetMainViewport()->Pos/Size instead of hardcoding those values.
374 // - In the interest of supporting multi-viewport applications (see 'docking' branch on github),
375 // always subtract draw_data->DisplayPos from clipping bounds to convert them to your viewport space.
376 // - Note that pcmd->ClipRect contains Min+Max bounds. Some graphics API may use Min+Max, other may use Min+Size (size being Max-Min)
377 MyEngineSetScissor(clip_min.x, clip_min.y, clip_max.x, clip_max.y);
378
379 // The texture for the draw call is specified by pcmd->GetTexID().
380 // The vast majority of draw calls will use the Dear ImGui texture atlas, which value you have set yourself during initialization.
381 MyEngineBindTexture((MyTexture*)pcmd->GetTexID());
382
383 // Render 'pcmd->ElemCount/3' indexed triangles.
384 // By default the indices ImDrawIdx are 16-bit, you can change them to 32-bit in imconfig.h if your engine doesn't support 16-bit indices.
385 MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer + pcmd->IdxOffset, vtx_buffer, pcmd->VtxOffset);
386 }
387 }
388 }
389 }
390
391
392 API BREAKING CHANGES
393 ====================
394
395 Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix.
396 Below is a change-log of API breaking changes only. If you are using one of the functions listed, expect to have to fix some code.
397 When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files.
398 You can read releases logs https://github.com/ocornut/imgui/releases for more details.
399
400 - 2023/03/09 (1.89.4) - renamed PushAllowKeyboardFocus()/PopAllowKeyboardFocus() to PushTabStop()/PopTabStop(). Kept inline redirection functions (will obsolete).
401 - 2023/03/09 (1.89.4) - tooltips: Added 'bool' return value to BeginTooltip() for API consistency. Please only submit contents and call EndTooltip() if BeginTooltip() returns true. In reality the function will _currently_ always return true, but further changes down the line may change this, best to clarify API sooner.
402 - 2023/02/15 (1.89.4) - moved the optional "courtesy maths operators" implementation from imgui_internal.h in imgui.h.
403 Even though we encourage using your own maths types and operators by setting up IM_VEC2_CLASS_EXTRA,
404 it has been frequently requested by people to use our own. We had an opt-in define which was
405 previously fulfilled in imgui_internal.h. It is now fulfilled in imgui.h. (#6164)
406 - OK: #define IMGUI_DEFINE_MATH_OPERATORS / #include "imgui.h" / #include "imgui_internal.h"
407 - Error: #include "imgui.h" / #define IMGUI_DEFINE_MATH_OPERATORS / #include "imgui_internal.h"
408 - 2023/02/07 (1.89.3) - backends: renamed "imgui_impl_sdl.cpp" to "imgui_impl_sdl2.cpp" and "imgui_impl_sdl.h" to "imgui_impl_sdl2.h". (#6146) This is in prevision for the future release of SDL3.
409 - 2022/10/26 (1.89) - commented out redirecting OpenPopupContextItem() which was briefly the name of OpenPopupOnItemClick() from 1.77 to 1.79.
410 - 2022/10/12 (1.89) - removed runtime patching of invalid "%f"/"%0.f" format strings for DragInt()/SliderInt(). This was obsoleted in 1.61 (May 2018). See 1.61 changelog for details.
411 - 2022/09/26 (1.89) - renamed and merged keyboard modifiers key enums and flags into a same set. Kept inline redirection enums (will obsolete).
412 - ImGuiKey_ModCtrl and ImGuiModFlags_Ctrl -> ImGuiMod_Ctrl
413 - ImGuiKey_ModShift and ImGuiModFlags_Shift -> ImGuiMod_Shift
414 - ImGuiKey_ModAlt and ImGuiModFlags_Alt -> ImGuiMod_Alt
415 - ImGuiKey_ModSuper and ImGuiModFlags_Super -> ImGuiMod_Super
416 the ImGuiKey_ModXXX were introduced in 1.87 and mostly used by backends.
417 the ImGuiModFlags_XXX have been exposed in imgui.h but not really used by any public api only by third-party extensions.
418 exceptionally commenting out the older ImGuiKeyModFlags_XXX names ahead of obsolescence schedule to reduce confusion and because they were not meant to be used anyway.
419 - 2022/09/20 (1.89) - ImGuiKey is now a typed enum, allowing ImGuiKey_XXX symbols to be named in debuggers.
420 this will require uses of legacy backend-dependent indices to be casted, e.g.
421 - with imgui_impl_glfw: IsKeyPressed(GLFW_KEY_A) -> IsKeyPressed((ImGuiKey)GLFW_KEY_A);
422 - with imgui_impl_win32: IsKeyPressed('A') -> IsKeyPressed((ImGuiKey)'A')
423 - etc. However if you are upgrading code you might well use the better, backend-agnostic IsKeyPressed(ImGuiKey_A) now!
424 - 2022/09/12 (1.89) - removed the bizarre legacy default argument for 'TreePush(const void* ptr = NULL)', always pass a pointer value explicitly. NULL/nullptr is ok but require cast, e.g. TreePush((void*)nullptr);
425 - 2022/09/05 (1.89) - commented out redirecting functions/enums names that were marked obsolete in 1.77 and 1.78 (June 2020):
426 - DragScalar(), DragScalarN(), DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(): For old signatures ending with (..., const char* format, float power = 1.0f) -> use (..., format ImGuiSliderFlags_Logarithmic) if power != 1.0f.
427 - SliderScalar(), SliderScalarN(), SliderFloat(), SliderFloat2(), SliderFloat3(), SliderFloat4(): For old signatures ending with (..., const char* format, float power = 1.0f) -> use (..., format ImGuiSliderFlags_Logarithmic) if power != 1.0f.
428 - BeginPopupContextWindow(const char*, ImGuiMouseButton, bool) -> use BeginPopupContextWindow(const char*, ImGuiPopupFlags)
429 - 2022/09/02 (1.89) - obsoleted using SetCursorPos()/SetCursorScreenPos() to extend parent window/cell boundaries.
430 this relates to when moving the cursor position beyond current boundaries WITHOUT submitting an item.
431 - previously this would make the window content size ~200x200:
432 Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + End();
433 - instead, please submit an item:
434 Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + Dummy(ImVec2(0,0)) + End();
435 - alternative:
436 Begin(...) + Dummy(ImVec2(200,200)) + End();
437 - content size is now only extended when submitting an item!
438 - with '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' this will now be detected and assert.
439 - without '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' this will silently be fixed until we obsolete it.
440 - 2022/08/03 (1.89) - changed signature of ImageButton() function. Kept redirection function (will obsolete).
441 - added 'const char* str_id' parameter + removed 'int frame_padding = -1' parameter.
442 - old signature: bool ImageButton(ImTextureID tex_id, ImVec2 size, ImVec2 uv0 = ImVec2(0,0), ImVec2 uv1 = ImVec2(1,1), int frame_padding = -1, ImVec4 bg_col = ImVec4(0,0,0,0), ImVec4 tint_col = ImVec4(1,1,1,1));
443 - used the ImTextureID value to create an ID. This was inconsistent with other functions, led to ID conflicts, and caused problems with engines using transient ImTextureID values.
444 - had a FramePadding override which was inconsistent with other functions and made the already-long signature even longer.
445 - new signature: bool ImageButton(const char* str_id, ImTextureID tex_id, ImVec2 size, ImVec2 uv0 = ImVec2(0,0), ImVec2 uv1 = ImVec2(1,1), ImVec4 bg_col = ImVec4(0,0,0,0), ImVec4 tint_col = ImVec4(1,1,1,1));
446 - requires an explicit identifier. You may still use e.g. PushID() calls and then pass an empty identifier.
447 - always uses style.FramePadding for padding, to be consistent with other buttons. You may use PushStyleVar() to alter this.
448 - 2022/07/08 (1.89) - inputs: removed io.NavInputs[] and ImGuiNavInput enum (following 1.87 changes).
449 - Official backends from 1.87+ -> no issue.
450 - Official backends from 1.60 to 1.86 -> will build and convert gamepad inputs, unless IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Need updating!
451 - Custom backends not writing to io.NavInputs[] -> no issue.
452 - Custom backends writing to io.NavInputs[] -> will build and convert gamepad inputs, unless IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Need fixing!
453 - TL;DR: Backends should call io.AddKeyEvent()/io.AddKeyAnalogEvent() with ImGuiKey_GamepadXXX values instead of filling io.NavInput[].
454 - 2022/06/15 (1.88) - renamed IMGUI_DISABLE_METRICS_WINDOW to IMGUI_DISABLE_DEBUG_TOOLS for correctness. kept support for old define (will obsolete).
455 - 2022/05/03 (1.88) - backends: osx: removed ImGui_ImplOSX_HandleEvent() from backend API in favor of backend automatically handling event capture. All ImGui_ImplOSX_HandleEvent() calls should be removed as they are now unnecessary.
456 - 2022/04/05 (1.88) - inputs: renamed ImGuiKeyModFlags to ImGuiModFlags. Kept inline redirection enums (will obsolete). This was never used in public API functions but technically present in imgui.h and ImGuiIO.
457 - 2022/01/20 (1.87) - inputs: reworded gamepad IO.
458 - Backend writing to io.NavInputs[] -> backend should call io.AddKeyEvent()/io.AddKeyAnalogEvent() with ImGuiKey_GamepadXXX values.
459 - 2022/01/19 (1.87) - sliders, drags: removed support for legacy arithmetic operators (+,+-,*,/) when inputing text. This doesn't break any api/code but a feature that used to be accessible by end-users (which seemingly no one used).
460 - 2022/01/17 (1.87) - inputs: reworked mouse IO.
461 - Backend writing to io.MousePos -> backend should call io.AddMousePosEvent()
462 - Backend writing to io.MouseDown[] -> backend should call io.AddMouseButtonEvent()
463 - Backend writing to io.MouseWheel -> backend should call io.AddMouseWheelEvent()
464 - Backend writing to io.MouseHoveredViewport -> backend should call io.AddMouseViewportEvent() [Docking branch w/ multi-viewports only]
465 note: for all calls to IO new functions, the Dear ImGui context should be bound/current.
466 read https://github.com/ocornut/imgui/issues/4921 for details.
467 - 2022/01/10 (1.87) - inputs: reworked keyboard IO. Removed io.KeyMap[], io.KeysDown[] in favor of calling io.AddKeyEvent(). Removed GetKeyIndex(), now unecessary. All IsKeyXXX() functions now take ImGuiKey values. All features are still functional until IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Read Changelog and Release Notes for details.
468 - IsKeyPressed(MY_NATIVE_KEY_XXX) -> use IsKeyPressed(ImGuiKey_XXX)
469 - IsKeyPressed(GetKeyIndex(ImGuiKey_XXX)) -> use IsKeyPressed(ImGuiKey_XXX)
470 - Backend writing to io.KeyMap[],io.KeysDown[] -> backend should call io.AddKeyEvent() (+ call io.SetKeyEventNativeData() if you want legacy user code to stil function with legacy key codes).
471 - Backend writing to io.KeyCtrl, io.KeyShift.. -> backend should call io.AddKeyEvent() with ImGuiMod_XXX values. *IF YOU PULLED CODE BETWEEN 2021/01/10 and 2021/01/27: We used to have a io.AddKeyModsEvent() function which was now replaced by io.AddKeyEvent() with ImGuiMod_XXX values.*
472 - one case won't work with backward compatibility: if your custom backend used ImGuiKey as mock native indices (e.g. "io.KeyMap[ImGuiKey_A] = ImGuiKey_A") because those values are now larger than the legacy KeyDown[] array. Will assert.
473 - inputs: added ImGuiKey_ModCtrl/ImGuiKey_ModShift/ImGuiKey_ModAlt/ImGuiKey_ModSuper values to submit keyboard modifiers using io.AddKeyEvent(), instead of writing directly to io.KeyCtrl, io.KeyShift, io.KeyAlt, io.KeySuper.
474 - 2022/01/05 (1.87) - inputs: renamed ImGuiKey_KeyPadEnter to ImGuiKey_KeypadEnter to align with new symbols. Kept redirection enum.
475 - 2022/01/05 (1.87) - removed io.ImeSetInputScreenPosFn() in favor of more flexible io.SetPlatformImeDataFn(). Removed 'void* io.ImeWindowHandle' in favor of writing to 'void* ImGuiViewport::PlatformHandleRaw'.
476 - 2022/01/01 (1.87) - commented out redirecting functions/enums names that were marked obsolete in 1.69, 1.70, 1.71, 1.72 (March-July 2019)
477 - ImGui::SetNextTreeNodeOpen() -> use ImGui::SetNextItemOpen()
478 - ImGui::GetContentRegionAvailWidth() -> use ImGui::GetContentRegionAvail().x
479 - ImGui::TreeAdvanceToLabelPos() -> use ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetTreeNodeToLabelSpacing());
480 - ImFontAtlas::CustomRect -> use ImFontAtlasCustomRect
481 - ImGuiColorEditFlags_RGB/HSV/HEX -> use ImGuiColorEditFlags_DisplayRGB/HSV/Hex
482 - 2021/12/20 (1.86) - backends: removed obsolete Marmalade backend (imgui_impl_marmalade.cpp) + example. Find last supported version at https://github.com/ocornut/imgui/wiki/Bindings
483 - 2021/11/04 (1.86) - removed CalcListClipping() function. Prefer using ImGuiListClipper which can return non-contiguous ranges. Please open an issue if you think you really need this function.
484 - 2021/08/23 (1.85) - removed GetWindowContentRegionWidth() function. keep inline redirection helper. can use 'GetWindowContentRegionMax().x - GetWindowContentRegionMin().x' instead for generally 'GetContentRegionAvail().x' is more useful.
485 - 2021/07/26 (1.84) - commented out redirecting functions/enums names that were marked obsolete in 1.67 and 1.69 (March 2019):
486 - ImGui::GetOverlayDrawList() -> use ImGui::GetForegroundDrawList()
487 - ImFont::GlyphRangesBuilder -> use ImFontGlyphRangesBuilder
488 - 2021/05/19 (1.83) - backends: obsoleted direct access to ImDrawCmd::TextureId in favor of calling ImDrawCmd::GetTexID().
489 - if you are using official backends from the source tree: you have nothing to do.
490 - if you have copied old backend code or using your own: change access to draw_cmd->TextureId to draw_cmd->GetTexID().
491 - 2021/03/12 (1.82) - upgraded ImDrawList::AddRect(), AddRectFilled(), PathRect() to use ImDrawFlags instead of ImDrawCornersFlags.
492 - ImDrawCornerFlags_TopLeft -> use ImDrawFlags_RoundCornersTopLeft
493 - ImDrawCornerFlags_BotRight -> use ImDrawFlags_RoundCornersBottomRight
494 - ImDrawCornerFlags_None -> use ImDrawFlags_RoundCornersNone etc.
495 flags now sanely defaults to 0 instead of 0x0F, consistent with all other flags in the API.
496 breaking: the default with rounding > 0.0f is now "round all corners" vs old implicit "round no corners":
497 - rounding == 0.0f + flags == 0 --> meant no rounding --> unchanged (common use)
498 - rounding > 0.0f + flags != 0 --> meant rounding --> unchanged (common use)
499 - rounding == 0.0f + flags != 0 --> meant no rounding --> unchanged (unlikely use)
500 - rounding > 0.0f + flags == 0 --> meant no rounding --> BREAKING (unlikely use): will now round all corners --> use ImDrawFlags_RoundCornersNone or rounding == 0.0f.
501 this ONLY matters for hard coded use of 0 + rounding > 0.0f. Use of named ImDrawFlags_RoundCornersNone (new) or ImDrawCornerFlags_None (old) are ok.
502 the old ImDrawCornersFlags used awkward default values of ~0 or 0xF (4 lower bits set) to signify "round all corners" and we sometimes encouraged using them as shortcuts.
503 legacy path still support use of hard coded ~0 or any value from 0x1 or 0xF. They will behave the same with legacy paths enabled (will assert otherwise).
504 - 2021/03/11 (1.82) - removed redirecting functions/enums names that were marked obsolete in 1.66 (September 2018):
505 - ImGui::SetScrollHere() -> use ImGui::SetScrollHereY()
506 - 2021/03/11 (1.82) - clarified that ImDrawList::PathArcTo(), ImDrawList::PathArcToFast() won't render with radius < 0.0f. Previously it sorts of accidentally worked but would generally lead to counter-clockwise paths and have an effect on anti-aliasing.
507 - 2021/03/10 (1.82) - upgraded ImDrawList::AddPolyline() and PathStroke() "bool closed" parameter to "ImDrawFlags flags". The matching ImDrawFlags_Closed value is guaranteed to always stay == 1 in the future.
508 - 2021/02/22 (1.82) - (*undone in 1.84*) win32+mingw: Re-enabled IME functions by default even under MinGW. In July 2016, issue #738 had me incorrectly disable those default functions for MinGW. MinGW users should: either link with -limm32, either set their imconfig file with '#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS'.
509 - 2021/02/17 (1.82) - renamed rarely used style.CircleSegmentMaxError (old default = 1.60f) to style.CircleTessellationMaxError (new default = 0.30f) as the meaning of the value changed.
510 - 2021/02/03 (1.81) - renamed ListBoxHeader(const char* label, ImVec2 size) to BeginListBox(). Kept inline redirection function (will obsolete).
511 - removed ListBoxHeader(const char* label, int items_count, int height_in_items = -1) in favor of specifying size. Kept inline redirection function (will obsolete).
512 - renamed ListBoxFooter() to EndListBox(). Kept inline redirection function (will obsolete).
513 - 2021/01/26 (1.81) - removed ImGuiFreeType::BuildFontAtlas(). Kept inline redirection function. Prefer using '#define IMGUI_ENABLE_FREETYPE', but there's a runtime selection path available too. The shared extra flags parameters (very rarely used) are now stored in ImFontAtlas::FontBuilderFlags.
514 - renamed ImFontConfig::RasterizerFlags (used by FreeType) to ImFontConfig::FontBuilderFlags.
515 - renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API.
516 - 2020/10/12 (1.80) - removed redirecting functions/enums that were marked obsolete in 1.63 (August 2018):
517 - ImGui::IsItemDeactivatedAfterChange() -> use ImGui::IsItemDeactivatedAfterEdit().
518 - ImGuiCol_ModalWindowDarkening -> use ImGuiCol_ModalWindowDimBg
519 - ImGuiInputTextCallback -> use ImGuiTextEditCallback
520 - ImGuiInputTextCallbackData -> use ImGuiTextEditCallbackData
521 - 2020/12/21 (1.80) - renamed ImDrawList::AddBezierCurve() to AddBezierCubic(), and PathBezierCurveTo() to PathBezierCubicCurveTo(). Kept inline redirection function (will obsolete).
522 - 2020/12/04 (1.80) - added imgui_tables.cpp file! Manually constructed project files will need the new file added!
523 - 2020/11/18 (1.80) - renamed undocumented/internals ImGuiColumnsFlags_* to ImGuiOldColumnFlags_* in prevision of incoming Tables API.
524 - 2020/11/03 (1.80) - renamed io.ConfigWindowsMemoryCompactTimer to io.ConfigMemoryCompactTimer as the feature will apply to other data structures
525 - 2020/10/14 (1.80) - backends: moved all backends files (imgui_impl_XXXX.cpp, imgui_impl_XXXX.h) from examples/ to backends/.
526 - 2020/10/12 (1.80) - removed redirecting functions/enums that were marked obsolete in 1.60 (April 2018):
527 - io.RenderDrawListsFn pointer -> use ImGui::GetDrawData() value and call the render function of your backend
528 - ImGui::IsAnyWindowFocused() -> use ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow)
529 - ImGui::IsAnyWindowHovered() -> use ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)
530 - ImGuiStyleVar_Count_ -> use ImGuiStyleVar_COUNT
531 - ImGuiMouseCursor_Count_ -> use ImGuiMouseCursor_COUNT
532 - removed redirecting functions names that were marked obsolete in 1.61 (May 2018):
533 - InputFloat (... int decimal_precision ...) -> use InputFloat (... const char* format ...) with format = "%.Xf" where X is your value for decimal_precision.
534 - same for InputFloat2()/InputFloat3()/InputFloat4() variants taking a `int decimal_precision` parameter.
535 - 2020/10/05 (1.79) - removed ImGuiListClipper: Renamed constructor parameters which created an ambiguous alternative to using the ImGuiListClipper::Begin() function, with misleading edge cases (note: imgui_memory_editor <0.40 from imgui_club/ used this old clipper API. Update your copy if needed).
536 - 2020/09/25 (1.79) - renamed ImGuiSliderFlags_ClampOnInput to ImGuiSliderFlags_AlwaysClamp. Kept redirection enum (will obsolete sooner because previous name was added recently).
537 - 2020/09/25 (1.79) - renamed style.TabMinWidthForUnselectedCloseButton to style.TabMinWidthForCloseButton.
538 - 2020/09/21 (1.79) - renamed OpenPopupContextItem() back to OpenPopupOnItemClick(), reverting the change from 1.77. For varieties of reason this is more self-explanatory.
539 - 2020/09/21 (1.79) - removed return value from OpenPopupOnItemClick() - returned true on mouse release on an item - because it is inconsistent with other popup APIs and makes others misleading. It's also and unnecessary: you can use IsWindowAppearing() after BeginPopup() for a similar result.
540 - 2020/09/17 (1.79) - removed ImFont::DisplayOffset in favor of ImFontConfig::GlyphOffset. DisplayOffset was applied after scaling and not very meaningful/useful outside of being needed by the default ProggyClean font. If you scaled this value after calling AddFontDefault(), this is now done automatically. It was also getting in the way of better font scaling, so let's get rid of it now!
541 - 2020/08/17 (1.78) - obsoleted use of the trailing 'float power=1.0f' parameter for DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(), DragFloatRange2(), DragScalar(), DragScalarN(), SliderFloat(), SliderFloat2(), SliderFloat3(), SliderFloat4(), SliderScalar(), SliderScalarN(), VSliderFloat() and VSliderScalar().
542 replaced the 'float power=1.0f' argument with integer-based flags defaulting to 0 (as with all our flags).
543 worked out a backward-compatibility scheme so hopefully most C++ codebase should not be affected. in short, when calling those functions:
544 - if you omitted the 'power' parameter (likely!), you are not affected.
545 - if you set the 'power' parameter to 1.0f (same as previous default value): 1/ your compiler may warn on float>int conversion, 2/ everything else will work. 3/ you can replace the 1.0f value with 0 to fix the warning, and be technically correct.
546 - if you set the 'power' parameter to >1.0f (to enable non-linear editing): 1/ your compiler may warn on float>int conversion, 2/ code will assert at runtime, 3/ in case asserts are disabled, the code will not crash and enable the _Logarithmic flag. 4/ you can replace the >1.0f value with ImGuiSliderFlags_Logarithmic to fix the warning/assert and get a _similar_ effect as previous uses of power >1.0f.
547 see https://github.com/ocornut/imgui/issues/3361 for all details.
548 kept inline redirection functions (will obsolete) apart for: DragFloatRange2(), VSliderFloat(), VSliderScalar(). For those three the 'float power=1.0f' version was removed directly as they were most unlikely ever used.
549 for shared code, you can version check at compile-time with `#if IMGUI_VERSION_NUM >= 17704`.
550 - obsoleted use of v_min > v_max in DragInt, DragFloat, DragScalar to lock edits (introduced in 1.73, was not demoed nor documented very), will be replaced by a more generic ReadOnly feature. You may use the ImGuiSliderFlags_ReadOnly internal flag in the meantime.
551 - 2020/06/23 (1.77) - removed BeginPopupContextWindow(const char*, int mouse_button, bool also_over_items) in favor of BeginPopupContextWindow(const char*, ImGuiPopupFlags flags) with ImGuiPopupFlags_NoOverItems.
552 - 2020/06/15 (1.77) - renamed OpenPopupOnItemClick() to OpenPopupContextItem(). Kept inline redirection function (will obsolete). [NOTE: THIS WAS REVERTED IN 1.79]
553 - 2020/06/15 (1.77) - removed CalcItemRectClosestPoint() entry point which was made obsolete and asserting in December 2017.
554 - 2020/04/23 (1.77) - removed unnecessary ID (first arg) of ImFontAtlas::AddCustomRectRegular().
555 - 2020/01/22 (1.75) - ImDrawList::AddCircle()/AddCircleFilled() functions don't accept negative radius any more.
556 - 2019/12/17 (1.75) - [undid this change in 1.76] made Columns() limited to 64 columns by asserting above that limit. While the current code technically supports it, future code may not so we're putting the restriction ahead.
557 - 2019/12/13 (1.75) - [imgui_internal.h] changed ImRect() default constructor initializes all fields to 0.0f instead of (FLT_MAX,FLT_MAX,-FLT_MAX,-FLT_MAX). If you used ImRect::Add() to create bounding boxes by adding multiple points into it, you may need to fix your initial value.
558 - 2019/12/08 (1.75) - removed redirecting functions/enums that were marked obsolete in 1.53 (December 2017):
559 - ShowTestWindow() -> use ShowDemoWindow()
560 - IsRootWindowFocused() -> use IsWindowFocused(ImGuiFocusedFlags_RootWindow)
561 - IsRootWindowOrAnyChildFocused() -> use IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows)
562 - SetNextWindowContentWidth(w) -> use SetNextWindowContentSize(ImVec2(w, 0.0f)
563 - GetItemsLineHeightWithSpacing() -> use GetFrameHeightWithSpacing()
564 - ImGuiCol_ChildWindowBg -> use ImGuiCol_ChildBg
565 - ImGuiStyleVar_ChildWindowRounding -> use ImGuiStyleVar_ChildRounding
566 - ImGuiTreeNodeFlags_AllowOverlapMode -> use ImGuiTreeNodeFlags_AllowItemOverlap
567 - IMGUI_DISABLE_TEST_WINDOWS -> use IMGUI_DISABLE_DEMO_WINDOWS
568 - 2019/12/08 (1.75) - obsoleted calling ImDrawList::PrimReserve() with a negative count (which was vaguely documented and rarely if ever used). Instead, we added an explicit PrimUnreserve() API.
569 - 2019/12/06 (1.75) - removed implicit default parameter to IsMouseDragging(int button = 0) to be consistent with other mouse functions (none of the other functions have it).
570 - 2019/11/21 (1.74) - ImFontAtlas::AddCustomRectRegular() now requires an ID larger than 0x110000 (instead of 0x10000) to conform with supporting Unicode planes 1-16 in a future update. ID below 0x110000 will now assert.
571 - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS to IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS for consistency.
572 - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_MATH_FUNCTIONS to IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS for consistency.
573 - 2019/10/22 (1.74) - removed redirecting functions/enums that were marked obsolete in 1.52 (October 2017):
574 - Begin() [old 5 args version] -> use Begin() [3 args], use SetNextWindowSize() SetNextWindowBgAlpha() if needed
575 - IsRootWindowOrAnyChildHovered() -> use IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows)
576 - AlignFirstTextHeightToWidgets() -> use AlignTextToFramePadding()
577 - SetNextWindowPosCenter() -> use SetNextWindowPos() with a pivot of (0.5f, 0.5f)
578 - ImFont::Glyph -> use ImFontGlyph
579 - 2019/10/14 (1.74) - inputs: Fixed a miscalculation in the keyboard/mouse "typematic" repeat delay/rate calculation, used by keys and e.g. repeating mouse buttons as well as the GetKeyPressedAmount() function.
580 if you were using a non-default value for io.KeyRepeatRate (previous default was 0.250), you can add +io.KeyRepeatDelay to it to compensate for the fix.
581 The function was triggering on: 0.0 and (delay+rate*N) where (N>=1). Fixed formula responds to (N>=0). Effectively it made io.KeyRepeatRate behave like it was set to (io.KeyRepeatRate + io.KeyRepeatDelay).
582 If you never altered io.KeyRepeatRate nor used GetKeyPressedAmount() this won't affect you.
583 - 2019/07/15 (1.72) - removed TreeAdvanceToLabelPos() which is rarely used and only does SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()). Kept redirection function (will obsolete).
584 - 2019/07/12 (1.72) - renamed ImFontAtlas::CustomRect to ImFontAtlasCustomRect. Kept redirection typedef (will obsolete).
585 - 2019/06/14 (1.72) - removed redirecting functions/enums names that were marked obsolete in 1.51 (June 2017): ImGuiCol_Column*, ImGuiSetCond_*, IsItemHoveredRect(), IsPosHoveringAnyWindow(), IsMouseHoveringAnyWindow(), IsMouseHoveringWindow(), IMGUI_ONCE_UPON_A_FRAME. Grep this log for details and new names, or see how they were implemented until 1.71.
586 - 2019/06/07 (1.71) - rendering of child window outer decorations (bg color, border, scrollbars) is now performed as part of the parent window. If you have
587 overlapping child windows in a same parent, and relied on their relative z-order to be mapped to their submission order, this will affect your rendering.
588 This optimization is disabled if the parent window has no visual output, because it appears to be the most common situation leading to the creation of overlapping child windows.
589 Please reach out if you are affected.
590 - 2019/05/13 (1.71) - renamed SetNextTreeNodeOpen() to SetNextItemOpen(). Kept inline redirection function (will obsolete).
591 - 2019/05/11 (1.71) - changed io.AddInputCharacter(unsigned short c) signature to io.AddInputCharacter(unsigned int c).
592 - 2019/04/29 (1.70) - improved ImDrawList thick strokes (>1.0f) preserving correct thickness up to 90 degrees angles (e.g. rectangles). If you have custom rendering using thick lines, they will appear thicker now.
593 - 2019/04/29 (1.70) - removed GetContentRegionAvailWidth(), use GetContentRegionAvail().x instead. Kept inline redirection function (will obsolete).
594 - 2019/03/04 (1.69) - renamed GetOverlayDrawList() to GetForegroundDrawList(). Kept redirection function (will obsolete).
595 - 2019/02/26 (1.69) - renamed ImGuiColorEditFlags_RGB/ImGuiColorEditFlags_HSV/ImGuiColorEditFlags_HEX to ImGuiColorEditFlags_DisplayRGB/ImGuiColorEditFlags_DisplayHSV/ImGuiColorEditFlags_DisplayHex. Kept redirection enums (will obsolete).
596 - 2019/02/14 (1.68) - made it illegal/assert when io.DisplayTime == 0.0f (with an exception for the first frame). If for some reason your time step calculation gives you a zero value, replace it with an arbitrarily small value!
597 - 2019/02/01 (1.68) - removed io.DisplayVisibleMin/DisplayVisibleMax (which were marked obsolete and removed from viewport/docking branch already).
598 - 2019/01/06 (1.67) - renamed io.InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead!
599 - 2019/01/06 (1.67) - renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Kept redirection typedef (will obsolete).
600 - 2018/12/20 (1.67) - made it illegal to call Begin("") with an empty string. This somehow half-worked before but had various undesirable side-effects.
601 - 2018/12/10 (1.67) - renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges as we are doing a large pass on configuration flags.
602 - 2018/10/12 (1.66) - renamed misc/stl/imgui_stl.* to misc/cpp/imgui_stdlib.* in prevision for other C++ helper files.
603 - 2018/09/28 (1.66) - renamed SetScrollHere() to SetScrollHereY(). Kept redirection function (will obsolete).
604 - 2018/09/06 (1.65) - renamed stb_truetype.h to imstb_truetype.h, stb_textedit.h to imstb_textedit.h, and stb_rect_pack.h to imstb_rectpack.h.
605 If you were conveniently using the imgui copy of those STB headers in your project you will have to update your include paths.
606 - 2018/09/05 (1.65) - renamed io.OptCursorBlink/io.ConfigCursorBlink to io.ConfigInputTextCursorBlink. (#1427)
607 - 2018/08/31 (1.64) - added imgui_widgets.cpp file, extracted and moved widgets code out of imgui.cpp into imgui_widgets.cpp. Re-ordered some of the code remaining in imgui.cpp.
608 NONE OF THE FUNCTIONS HAVE CHANGED. THE CODE IS SEMANTICALLY 100% IDENTICAL, BUT _EVERY_ FUNCTION HAS BEEN MOVED.
609 Because of this, any local modifications to imgui.cpp will likely conflict when you update. Read docs/CHANGELOG.txt for suggestions.
610 - 2018/08/22 (1.63) - renamed IsItemDeactivatedAfterChange() to IsItemDeactivatedAfterEdit() for consistency with new IsItemEdited() API. Kept redirection function (will obsolete soonish as IsItemDeactivatedAfterChange() is very recent).
611 - 2018/08/21 (1.63) - renamed ImGuiTextEditCallback to ImGuiInputTextCallback, ImGuiTextEditCallbackData to ImGuiInputTextCallbackData for consistency. Kept redirection types (will obsolete).
612 - 2018/08/21 (1.63) - removed ImGuiInputTextCallbackData::ReadOnly since it is a duplication of (ImGuiInputTextCallbackData::Flags & ImGuiInputTextFlags_ReadOnly).
613 - 2018/08/01 (1.63) - removed per-window ImGuiWindowFlags_ResizeFromAnySide beta flag in favor of a global io.ConfigResizeWindowsFromEdges [update 1.67 renamed to ConfigWindowsResizeFromEdges] to enable the feature.
614 - 2018/08/01 (1.63) - renamed io.OptCursorBlink to io.ConfigCursorBlink [-> io.ConfigInputTextCursorBlink in 1.65], io.OptMacOSXBehaviors to ConfigMacOSXBehaviors for consistency.
615 - 2018/07/22 (1.63) - changed ImGui::GetTime() return value from float to double to avoid accumulating floating point imprecisions over time.
616 - 2018/07/08 (1.63) - style: renamed ImGuiCol_ModalWindowDarkening to ImGuiCol_ModalWindowDimBg for consistency with other features. Kept redirection enum (will obsolete).
617 - 2018/06/08 (1.62) - examples: the imgui_impl_XXX files have been split to separate platform (Win32, GLFW, SDL2, etc.) from renderer (DX11, OpenGL, Vulkan, etc.).
618 old backends will still work as is, however prefer using the separated backends as they will be updated to support multi-viewports.
619 when adopting new backends follow the main.cpp code of your preferred examples/ folder to know which functions to call.
620 in particular, note that old backends called ImGui::NewFrame() at the end of their ImGui_ImplXXXX_NewFrame() function.
621 - 2018/06/06 (1.62) - renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish other variants and discourage using the full set.
622 - 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details.
623 - 2018/05/03 (1.61) - DragInt(): the default compile-time format string has been changed from "%.0f" to "%d", as we are not using integers internally any more.
624 If you used DragInt() with custom format strings, make sure you change them to use %d or an integer-compatible format.
625 To honor backward-compatibility, the DragInt() code will currently parse and modify format strings to replace %*f with %d, giving time to users to upgrade their code.
626 If you have IMGUI_DISABLE_OBSOLETE_FUNCTIONS enabled, the code will instead assert! You may run a reg-exp search on your codebase for e.g. "DragInt.*%f" to help you find them.
627 - 2018/04/28 (1.61) - obsoleted InputFloat() functions taking an optional "int decimal_precision" in favor of an equivalent and more flexible "const char* format",
628 consistent with other functions. Kept redirection functions (will obsolete).
629 - 2018/04/09 (1.61) - IM_DELETE() helper function added in 1.60 doesn't clear the input _pointer_ reference, more consistent with expectation and allows passing r-value.
630 - 2018/03/20 (1.60) - renamed io.WantMoveMouse to io.WantSetMousePos for consistency and ease of understanding (was added in 1.52, _not_ used by core and only honored by some backend ahead of merging the Nav branch).
631 - 2018/03/12 (1.60) - removed ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered as the closing cross uses regular button colors now.
632 - 2018/03/08 (1.60) - changed ImFont::DisplayOffset.y to default to 0 instead of +1. Fixed rounding of Ascent/Descent to match TrueType renderer. If you were adding or subtracting to ImFont::DisplayOffset check if your fonts are correctly aligned vertically.
633 - 2018/03/03 (1.60) - renamed ImGuiStyleVar_Count_ to ImGuiStyleVar_COUNT and ImGuiMouseCursor_Count_ to ImGuiMouseCursor_COUNT for consistency with other public enums.
634 - 2018/02/18 (1.60) - BeginDragDropSource(): temporarily removed the optional mouse_button=0 parameter because it is not really usable in many situations at the moment.
635 - 2018/02/16 (1.60) - obsoleted the io.RenderDrawListsFn callback, you can call your graphics engine render function after ImGui::Render(). Use ImGui::GetDrawData() to retrieve the ImDrawData* to display.
636 - 2018/02/07 (1.60) - reorganized context handling to be more explicit,
637 - YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END.
638 - removed Shutdown() function, as DestroyContext() serve this purpose.
639 - you may pass a ImFontAtlas* pointer to CreateContext() to share a font atlas between contexts. Otherwise CreateContext() will create its own font atlas instance.
640 - removed allocator parameters from CreateContext(), they are now setup with SetAllocatorFunctions(), and shared by all contexts.
641 - removed the default global context and font atlas instance, which were confusing for users of DLL reloading and users of multiple contexts.
642 - 2018/01/31 (1.60) - moved sample TTF files from extra_fonts/ to misc/fonts/. If you loaded files directly from the imgui repo you may need to update your paths.
643 - 2018/01/11 (1.60) - obsoleted IsAnyWindowHovered() in favor of IsWindowHovered(ImGuiHoveredFlags_AnyWindow). Kept redirection function (will obsolete).
644 - 2018/01/11 (1.60) - obsoleted IsAnyWindowFocused() in favor of IsWindowFocused(ImGuiFocusedFlags_AnyWindow). Kept redirection function (will obsolete).
645 - 2018/01/03 (1.60) - renamed ImGuiSizeConstraintCallback to ImGuiSizeCallback, ImGuiSizeConstraintCallbackData to ImGuiSizeCallbackData.
646 - 2017/12/29 (1.60) - removed CalcItemRectClosestPoint() which was weird and not really used by anyone except demo code. If you need it it's easy to replicate on your side.
647 - 2017/12/24 (1.53) - renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). Kept redirection function (will obsolete).
648 - 2017/12/21 (1.53) - ImDrawList: renamed style.AntiAliasedShapes to style.AntiAliasedFill for consistency and as a way to explicitly break code that manipulate those flag at runtime. You can now manipulate ImDrawList::Flags
649 - 2017/12/21 (1.53) - ImDrawList: removed 'bool anti_aliased = true' final parameter of ImDrawList::AddPolyline() and ImDrawList::AddConvexPolyFilled(). Prefer manipulating ImDrawList::Flags if you need to toggle them during the frame.
650 - 2017/12/14 (1.53) - using the ImGuiWindowFlags_NoScrollWithMouse flag on a child window forwards the mouse wheel event to the parent window, unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set.
651 - 2017/12/13 (1.53) - renamed GetItemsLineHeightWithSpacing() to GetFrameHeightWithSpacing(). Kept redirection function (will obsolete).
652 - 2017/12/13 (1.53) - obsoleted IsRootWindowFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootWindow). Kept redirection function (will obsolete).
653 - obsoleted IsRootWindowOrAnyChildFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows). Kept redirection function (will obsolete).
654 - 2017/12/12 (1.53) - renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. Kept redirection enum (will obsolete).
655 - 2017/12/10 (1.53) - removed SetNextWindowContentWidth(), prefer using SetNextWindowContentSize(). Kept redirection function (will obsolete).
656 - 2017/11/27 (1.53) - renamed ImGuiTextBuffer::append() helper to appendf(), appendv() to appendfv(). If you copied the 'Log' demo in your code, it uses appendv() so that needs to be renamed.
657 - 2017/11/18 (1.53) - Style, Begin: removed ImGuiWindowFlags_ShowBorders window flag. Borders are now fully set up in the ImGuiStyle structure (see e.g. style.FrameBorderSize, style.WindowBorderSize). Use ImGui::ShowStyleEditor() to look them up.
658 Please note that the style system will keep evolving (hopefully stabilizing in Q1 2018), and so custom styles will probably subtly break over time. It is recommended you use the StyleColorsClassic(), StyleColorsDark(), StyleColorsLight() functions.
659 - 2017/11/18 (1.53) - Style: removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency.
660 - 2017/11/18 (1.53) - Style: renamed ImGuiCol_ChildWindowBg to ImGuiCol_ChildBg.
661 - 2017/11/18 (1.53) - Style: renamed style.ChildWindowRounding to style.ChildRounding, ImGuiStyleVar_ChildWindowRounding to ImGuiStyleVar_ChildRounding.
662 - 2017/11/02 (1.53) - obsoleted IsRootWindowOrAnyChildHovered() in favor of using IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows);
663 - 2017/10/24 (1.52) - renamed IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS to IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS for consistency.
664 - 2017/10/20 (1.52) - changed IsWindowHovered() default parameters behavior to return false if an item is active in another window (e.g. click-dragging item from another window to this window). You can use the newly introduced IsWindowHovered() flags to requests this specific behavior if you need it.
665 - 2017/10/20 (1.52) - marked IsItemHoveredRect()/IsMouseHoveringWindow() as obsolete, in favor of using the newly introduced flags for IsItemHovered() and IsWindowHovered(). See https://github.com/ocornut/imgui/issues/1382 for details.
666 removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting.
667 IsItemHoveredRect() --> IsItemHovered(ImGuiHoveredFlags_RectOnly)
668 IsMouseHoveringAnyWindow() --> IsWindowHovered(ImGuiHoveredFlags_AnyWindow)
669 IsMouseHoveringWindow() --> IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) [weird, old behavior]
670 - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead!
671 - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete).
672 - 2017/09/26 (1.52) - renamed ImFont::Glyph to ImFontGlyph. Kept redirection typedef (will obsolete).
673 - 2017/09/25 (1.52) - removed SetNextWindowPosCenter() because SetNextWindowPos() now has the optional pivot information to do the same and more. Kept redirection function (will obsolete).
674 - 2017/08/25 (1.52) - io.MousePos needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing. Previously ImVec2(-1,-1) was enough but we now accept negative mouse coordinates. In your backend if you need to support unavailable mouse, make sure to replace "io.MousePos = ImVec2(-1,-1)" with "io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX)".
675 - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)!
676 - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete).
677 - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete).
678 - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency.
679 - 2017/08/20 (1.51) - added PushStyleColor(ImGuiCol idx, ImU32 col) overload, which _might_ cause an "ambiguous call" compilation error if you are using ImColor() with implicit cast. Cast to ImU32 or ImVec4 explicily to fix.
680 - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame type.
681 - 2017/08/15 (1.51) - changed parameter order for BeginPopupContextWindow() from (const char*,int buttons,bool also_over_items) to (const char*,int buttons,bool also_over_items). Note that most calls relied on default parameters completely.
682 - 2017/08/13 (1.51) - renamed ImGuiCol_Column to ImGuiCol_Separator, ImGuiCol_ColumnHovered to ImGuiCol_SeparatorHovered, ImGuiCol_ColumnActive to ImGuiCol_SeparatorActive. Kept redirection enums (will obsolete).
683 - 2017/08/11 (1.51) - renamed ImGuiSetCond_Always to ImGuiCond_Always, ImGuiSetCond_Once to ImGuiCond_Once, ImGuiSetCond_FirstUseEver to ImGuiCond_FirstUseEver, ImGuiSetCond_Appearing to ImGuiCond_Appearing. Kept redirection enums (will obsolete).
684 - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton().
685 - 2017/08/08 (1.51) - removed ColorEditMode() and ImGuiColorEditMode in favor of ImGuiColorEditFlags and parameters to the various Color*() functions. The SetColorEditOptions() allows to initialize default but the user can still change them with right-click context menu.
686 - changed prototype of 'ColorEdit4(const char* label, float col[4], bool show_alpha = true)' to 'ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0)', where passing flags = 0x01 is a safe no-op (hello dodgy backward compatibility!). - check and run the demo window, under "Color/Picker Widgets", to understand the various new options.
687 - changed prototype of rarely used 'ColorButton(ImVec4 col, bool small_height = false, bool outline_border = true)' to 'ColorButton(const char* desc_id, ImVec4 col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0, 0))'
688 - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse
689 - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset.
690 - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity.
691 - 2016/11/06 (1.50) - BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetID() and use it instead of passing string to BeginChild().
692 - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it.
693 - 2016/09/25 (1.50) - style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc.
694 - 2016/07/30 (1.50) - SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully, breakage should be minimal.
695 - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore.
696 If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you, otherwise if <1.0f you need to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar.
697 This helper function will convert an old TitleBg/TitleBgActive color into a new one with the same visual output, given the OLD color and the OLD WindowBg color:
698 ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col) { float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a; return ImVec4((win_bg_col.x * win_bg_col.w + title_bg_col.x) * k, (win_bg_col.y * win_bg_col.w + title_bg_col.y) * k, (win_bg_col.z * win_bg_col.w + title_bg_col.z) * k, new_a); }
699 If this is confusing, pick the RGB value from title bar from an old screenshot and apply this as TitleBg/TitleBgActive. Or you may just create TitleBgActive from a tweaked TitleBg color.
700 - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext().
701 - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection.
702 - 2016/05/01 (1.49) - obsoleted old signature of CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false) as extra parameters were badly designed and rarely used. You can replace the "default_open = true" flag in new API with CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen).
703 - 2016/04/26 (1.49) - changed ImDrawList::PushClipRect(ImVec4 rect) to ImDrawList::PushClipRect(Imvec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false). Note that higher-level ImGui::PushClipRect() is preferable because it will clip at logic/widget level, whereas ImDrawList::PushClipRect() only affect your renderer.
704 - 2016/04/03 (1.48) - removed style.WindowFillAlphaDefault setting which was redundant. Bake default BG alpha inside style.Colors[ImGuiCol_WindowBg] and all other Bg color values. (ref GitHub issue #337).
705 - 2016/04/03 (1.48) - renamed ImGuiCol_TooltipBg to ImGuiCol_PopupBg, used by popups/menus and tooltips. popups/menus were previously using ImGuiCol_WindowBg. (ref github issue #337)
706 - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete).
707 - 2016/03/02 (1.48) - InputText() completion/history/always callbacks: if you modify the text buffer manually (without using DeleteChars()/InsertChars() helper) you need to maintain the BufTextLen field. added an assert.
708 - 2016/01/23 (1.48) - fixed not honoring exact width passed to PushItemWidth(), previously it would add extra FramePadding.x*2 over that width. if you had manual pixel-perfect alignment in place it might affect you.
709 - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis.
710 - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete.
711 - 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position.
712 GetCursorPos()/SetCursorPos() functions now include the scrolled amount. It shouldn't affect the majority of users, but take note that SetCursorPosX(100.0f) puts you at +100 from the starting x position which may include scrolling, not at +100 from the window left side.
713 GetContentRegionMax()/GetWindowContentRegionMin()/GetWindowContentRegionMax() functions allow include the scrolled amount. Typically those were used in cases where no scrolling would happen so it may not be a problem, but watch out!
714 - 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize
715 - 2015/08/05 (1.44) - split imgui.cpp into extra files: imgui_demo.cpp imgui_draw.cpp imgui_internal.h that you need to add to your project.
716 - 2015/07/18 (1.44) - fixed angles in ImDrawList::PathArcTo(), PathArcToFast() (introduced in 1.43) being off by an extra PI for no justifiable reason
717 - 2015/07/14 (1.43) - add new ImFontAtlas::AddFont() API. For the old AddFont***, moved the 'font_no' parameter of ImFontAtlas::AddFont** functions to the ImFontConfig structure.
718 you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text.
719 - 2015/07/08 (1.43) - switched rendering data to use indexed rendering. this is saving a fair amount of CPU/GPU and enables us to get anti-aliasing for a marginal cost.
720 this necessary change will break your rendering function! the fix should be very easy. sorry for that :(
721 - if you are using a vanilla copy of one of the imgui_impl_XXX.cpp provided in the example, you just need to update your copy and you can ignore the rest.
722 - the signature of the io.RenderDrawListsFn handler has changed!
723 old: ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
724 new: ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data).
725 parameters: 'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount'
726 ImDrawList: 'commands' becomes 'CmdBuffer', 'vtx_buffer' becomes 'VtxBuffer', 'IdxBuffer' is new.
727 ImDrawCmd: 'vtx_count' becomes 'ElemCount', 'clip_rect' becomes 'ClipRect', 'user_callback' becomes 'UserCallback', 'texture_id' becomes 'TextureId'.
728 - each ImDrawList now contains both a vertex buffer and an index buffer. For each command, render ElemCount/3 triangles using indices from the index buffer.
729 - if you REALLY cannot render indexed primitives, you can call the draw_data->DeIndexAllBuffers() method to de-index the buffers. This is slow and a waste of CPU/GPU. Prefer using indexed rendering!
730 - refer to code in the examples/ folder or ask on the GitHub if you are unsure of how to upgrade. please upgrade!
731 - 2015/07/10 (1.43) - changed SameLine() parameters from int to float.
732 - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete).
733 - 2015/07/02 (1.42) - renamed GetScrollPosY() to GetScrollY(). Necessary to reduce confusion along with other scrolling functions, because positions (e.g. cursor position) are not equivalent to scrolling amount.
734 - 2015/06/14 (1.41) - changed ImageButton() default bg_col parameter from (0,0,0,1) (black) to (0,0,0,0) (transparent) - makes a difference when texture have transparence
735 - 2015/06/14 (1.41) - changed Selectable() API from (label, selected, size) to (label, selected, flags, size). Size override should have been rarely used. Sorry!
736 - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete).
737 - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete).
738 - 2015/05/27 (1.40) - removed the third 'repeat_if_held' parameter from Button() - sorry! it was rarely used and inconsistent. Use PushButtonRepeat(true) / PopButtonRepeat() to enable repeat on desired buttons.
739 - 2015/05/11 (1.40) - changed BeginPopup() API, takes a string identifier instead of a bool. ImGui needs to manage the open/closed state of popups. Call OpenPopup() to actually set the "open" state of a popup. BeginPopup() returns true if the popup is opened.
740 - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same).
741 - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50.
742 - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API
743 - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive.
744 - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead.
745 - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50.
746 - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing
747 - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50.
748 - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing)
749 - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50.
750 - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once.
751 - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now.
752 - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior
753 - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing()
754 - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused)
755 - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions.
756 - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader.
757 - 2015/01/11 (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels.
758 - old: const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); [..Upload texture to GPU..];
759 - new: unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); [..Upload texture to GPU..]; io.Fonts->SetTexID(YourTexIdentifier);
760 you now have more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs. It is now recommended that you sample the font texture with bilinear interpolation.
761 - 2015/01/11 (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to call io.Fonts->SetTexID()
762 - 2015/01/11 (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix)
763 - 2015/01/11 (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets
764 - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver)
765 - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph)
766 - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility
767 - 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered()
768 - 2014/10/02 (1.14) - renamed IMGUI_INCLUDE_IMGUI_USER_CPP to IMGUI_INCLUDE_IMGUI_USER_INL and imgui_user.cpp to imgui_user.inl (more IDE friendly)
769 - 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity)
770 - 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale()
771 - 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn
772 - 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically)
773 - 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite
774 - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes
775
776
777 FREQUENTLY ASKED QUESTIONS (FAQ)
778 ================================
779
780 Read all answers online:
781 https://www.dearimgui.org/faq or https://github.com/ocornut/imgui/blob/master/docs/FAQ.md (same url)
782 Read all answers locally (with a text editor or ideally a Markdown viewer):
783 docs/FAQ.md
784 Some answers are copied down here to facilitate searching in code.
785
786 Q&A: Basics
787 ===========
788
789 Q: Where is the documentation?
790 A: This library is poorly documented at the moment and expects the user to be acquainted with C/C++.
791 - Run the examples/ and explore them.
792 - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
793 - The demo covers most features of Dear ImGui, so you can read the code and see its output.
794 - See documentation and comments at the top of imgui.cpp + effectively imgui.h.
795 - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the
796 examples/ folder to explain how to integrate Dear ImGui with your own engine/application.
797 - The Wiki (https://github.com/ocornut/imgui/wiki) has many resources and links.
798 - The Glossary (https://github.com/ocornut/imgui/wiki/Glossary) page also may be useful.
799 - Your programming IDE is your friend, find the type or function declaration to find comments
800 associated with it.
801
802 Q: What is this library called?
803 Q: Which version should I get?
804 >> This library is called "Dear ImGui", please don't call it "ImGui" :)
805 >> See https://www.dearimgui.org/faq for details.
806
807 Q&A: Integration
808 ================
809
810 Q: How to get started?
811 A: Read 'PROGRAMMER GUIDE' above. Read examples/README.txt.
812
813 Q: How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?
814 A: You should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags!
815 >> See https://www.dearimgui.org/faq for a fully detailed answer. You really want to read this.
816
817 Q. How can I enable keyboard controls?
818 Q: How can I use this without a mouse, without a keyboard or without a screen? (gamepad, input share, remote display)
819 Q: I integrated Dear ImGui in my engine and little squares are showing instead of text...
820 Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around...
821 Q: I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries...
822 >> See https://www.dearimgui.org/faq
823
824 Q&A: Usage
825 ----------
826
827 Q: About the ID Stack system..
828 - Why is my widget not reacting when I click on it?
829 - How can I have widgets with an empty label?
830 - How can I have multiple widgets with the same label?
831 - How can I have multiple windows with the same label?
832 Q: How can I display an image? What is ImTextureID, how does it work?
833 Q: How can I use my own math types instead of ImVec2/ImVec4?
834 Q: How can I interact with standard C++ types (such as std::string and std::vector)?
835 Q: How can I display custom shapes? (using low-level ImDrawList API)
836 >> See https://www.dearimgui.org/faq
837
838 Q&A: Fonts, Text
839 ================
840
841 Q: How should I handle DPI in my application?
842 Q: How can I load a different font than the default?
843 Q: How can I easily use icons in my application?
844 Q: How can I load multiple fonts?
845 Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic?
846 >> See https://www.dearimgui.org/faq and https://github.com/ocornut/imgui/edit/master/docs/FONTS.md
847
848 Q&A: Concerns
849 =============
850
851 Q: Who uses Dear ImGui?
852 Q: Can you create elaborate/serious tools with Dear ImGui?
853 Q: Can you reskin the look of Dear ImGui?
854 Q: Why using C++ (as opposed to C)?
855 >> See https://www.dearimgui.org/faq
856
857 Q&A: Community
858 ==============
859
860 Q: How can I help?
861 A: - Businesses: please reach out to "contact AT dearimgui.com" if you work in a place using Dear ImGui!
862 We can discuss ways for your company to fund development via invoiced technical support, maintenance or sponsoring contacts.
863 This is among the most useful thing you can do for Dear ImGui. With increased funding, we can hire more people working on this project.
864 - Individuals: you can support continued development via PayPal donations. See README.
865 - If you are experienced with Dear ImGui and C++, look at the GitHub issues, look at the Wiki, read docs/TODO.txt
866 and see how you want to help and can help!
867 - Disclose your usage of Dear ImGui via a dev blog post, a tweet, a screenshot, a mention somewhere etc.
868 You may post screenshot or links in the gallery threads. Visuals are ideal as they inspire other programmers.
869 But even without visuals, disclosing your use of dear imgui helps the library grow credibility, and help other teams and programmers with taking decisions.
870 - If you have issues or if you need to hack into the library, even if you don't expect any support it is useful that you share your issues (on GitHub or privately).
871
872*/
873
874//-------------------------------------------------------------------------
875// [SECTION] INCLUDES
876//-------------------------------------------------------------------------
877
878#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
879#define _CRT_SECURE_NO_WARNINGS
880#endif
881
882#ifndef IMGUI_DEFINE_MATH_OPERATORS
883#define IMGUI_DEFINE_MATH_OPERATORS
884#endif
885
886#include "imgui.h"
887#ifndef IMGUI_DISABLE
888#include "imgui_internal.h"
889
890// System includes
891#include <stdio.h> // vsnprintf, sscanf, printf
892#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
893#include <stddef.h> // intptr_t
894#else
895#include <stdint.h> // intptr_t
896#endif
897
898// [Windows] On non-Visual Studio compilers, we default to IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS unless explicitly enabled
899#if defined(_WIN32) && !defined(_MSC_VER) && !defined(IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
900#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
901#endif
902
903// [Windows] OS specific includes (optional)
904#if defined(_WIN32) && defined(IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
905#define IMGUI_DISABLE_WIN32_FUNCTIONS
906#endif
907#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
908#ifndef WIN32_LEAN_AND_MEAN
909#define WIN32_LEAN_AND_MEAN
910#endif
911#ifndef NOMINMAX
912#define NOMINMAX
913#endif
914#ifndef __MINGW32__
915#include <Windows.h> // _wfopen, OpenClipboard
916#else
917#include <windows.h>
918#endif
919#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) // UWP doesn't have all Win32 functions
920#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS
921#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
922#endif
923#endif
924
925// [Apple] OS specific includes
926#if defined(__APPLE__)
927#include <TargetConditionals.h>
928#endif
929
930// Visual Studio warnings
931#ifdef _MSC_VER
932#pragma warning (disable: 4127) // condition expression is constant
933#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
934#if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later
935#pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types
936#endif
937#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to an 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2).
938#pragma warning (disable: 26495) // [Static Analyzer] Variable 'XXX' is uninitialized. Always initialize a member variable (type.6).
939#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3).
940#endif
941
942// Clang/GCC warnings with -Weverything
943#if defined(__clang__)
944#if __has_warning("-Wunknown-warning-option")
945#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great!
946#endif
947#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx'
948#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse.
949#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok.
950#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning: format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code.
951#pragma clang diagnostic ignored "-Wexit-time-destructors" // warning: declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals.
952#pragma clang diagnostic ignored "-Wglobal-constructors" // warning: declaration requires a global destructor // similar to above, not sure what the exact difference is.
953#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
954#pragma clang diagnostic ignored "-Wformat-pedantic" // warning: format specifies type 'void *' but the argument has type 'xxxx *' // unreasonable, would lead to casting every %p arg to void*. probably enabled by -pedantic.
955#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning: cast to 'void *' from smaller integer type 'int'
956#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0
957#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.
958#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
959#elif defined(__GNUC__)
960// We disable -Wpragmas because GCC doesn't provide a has_warning equivalent and some forks/patches may not follow the warning/version association.
961#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
962#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
963#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size
964#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*'
965#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
966#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
967#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked
968#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false
969#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
970#endif
971
972// Debug options
973#define IMGUI_DEBUG_NAV_SCORING 0 // Display navigation scoring preview when hovering items. Display last moving direction matches when holding CTRL
974#define IMGUI_DEBUG_NAV_RECTS 0 // Display the reference navigation rectangle for each window
975#define IMGUI_DEBUG_INI_SETTINGS 0 // Save additional comments in .ini file (particularly helps for Docking, but makes saving slower)
976
977// When using CTRL+TAB (or Gamepad Square+L/R) we delay the visual a little in order to reduce visual noise doing a fast switch.
978static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; // Time before the highlight and screen dimming starts fading in
979static const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f; // Time before the window list starts to appear
980
981// Window resizing from edges (when io.ConfigWindowsResizeFromEdges = true and ImGuiBackendFlags_HasMouseCursors is set in io.BackendFlags by backend)
982static const float WINDOWS_HOVER_PADDING = 4.0f; // Extend outside window for hovering/resizing (maxxed with TouchPadding) and inside windows for borders. Affect FindHoveredWindow().
983static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduce visual noise by only highlighting the border after a certain time.
984static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 0.70f; // Lock scrolled window (so it doesn't pick child windows that are scrolling through) for a certain time, unless mouse moved.
985
986//-------------------------------------------------------------------------
987// [SECTION] FORWARD DECLARATIONS
988//-------------------------------------------------------------------------
989
990static void SetCurrentWindow(ImGuiWindow* window);
991static void FindHoveredWindow();
992static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags);
993static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window);
994
995static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* draw_list);
996static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window);
997
998// Settings
999static void WindowSettingsHandler_ClearAll(ImGuiContext*, ImGuiSettingsHandler*);
1000static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name);
1001static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line);
1002static void WindowSettingsHandler_ApplyAll(ImGuiContext*, ImGuiSettingsHandler*);
1003static void WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSettingsHandler*, ImGuiTextBuffer* buf);
1004
1005// Platform Dependents default implementation for IO functions
1006static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx);
1007static void SetClipboardTextFn_DefaultImpl(void* user_data_ctx, const char* text);
1008static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport* viewport, ImGuiPlatformImeData* data);
1009
1010namespace ImGui
1011{
1012// Navigation
1013static void NavUpdate();
1014static void NavUpdateWindowing();
1015static void NavUpdateWindowingOverlay();
1016static void NavUpdateCancelRequest();
1017static void NavUpdateCreateMoveRequest();
1018static void NavUpdateCreateTabbingRequest();
1019static float NavUpdatePageUpPageDown();
1020static inline void NavUpdateAnyRequestFlag();
1021static void NavUpdateCreateWrappingRequest();
1022static void NavEndFrame();
1023static bool NavScoreItem(ImGuiNavItemData* result);
1024static void NavApplyItemToResult(ImGuiNavItemData* result);
1025static void NavProcessItem();
1026static void NavProcessItemForTabbingRequest(ImGuiID id, ImGuiItemFlags item_flags, ImGuiNavMoveFlags move_flags);
1027static ImVec2 NavCalcPreferredRefPos();
1028static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window);
1029static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window);
1030static void NavRestoreLayer(ImGuiNavLayer layer);
1031static void NavRestoreHighlightAfterMove();
1032static int FindWindowFocusIndex(ImGuiWindow* window);
1033
1034// Error Checking and Debug Tools
1035static void ErrorCheckNewFrameSanityChecks();
1036static void ErrorCheckEndFrameSanityChecks();
1037static void UpdateDebugToolItemPicker();
1038static void UpdateDebugToolStackQueries();
1039
1040// Inputs
1041static void UpdateKeyboardInputs();
1042static void UpdateMouseInputs();
1043static void UpdateMouseWheel();
1044static void UpdateKeyRoutingTable(ImGuiKeyRoutingTable* rt);
1045
1046// Misc
1047static void UpdateSettings();
1048static bool UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect);
1049static void RenderWindowOuterBorders(ImGuiWindow* window);
1050static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, bool handle_borders_and_resize_grips, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size);
1051static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open);
1052static void RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col);
1053static void RenderDimmedBackgrounds();
1054static ImGuiWindow* FindBlockingModal(ImGuiWindow* window);
1055
1056// Viewports
1057static void UpdateViewportsNewFrame();
1058
1059}
1060
1061//-----------------------------------------------------------------------------
1062// [SECTION] CONTEXT AND MEMORY ALLOCATORS
1063//-----------------------------------------------------------------------------
1064
1065// DLL users:
1066// - Heaps and globals are not shared across DLL boundaries!
1067// - You will need to call SetCurrentContext() + SetAllocatorFunctions() for each static/DLL boundary you are calling from.
1068// - Same applies for hot-reloading mechanisms that are reliant on reloading DLL (note that many hot-reloading mechanisms work without DLL).
1069// - Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
1070// - Confused? In a debugger: add GImGui to your watch window and notice how its value changes depending on your current location (which DLL boundary you are in).
1071
1072// Current context pointer. Implicitly used by all Dear ImGui functions. Always assumed to be != NULL.
1073// - ImGui::CreateContext() will automatically set this pointer if it is NULL.
1074// Change to a different context by calling ImGui::SetCurrentContext().
1075// - Important: Dear ImGui functions are not thread-safe because of this pointer.
1076// If you want thread-safety to allow N threads to access N different contexts:
1077// - Change this variable to use thread local storage so each thread can refer to a different context, in your imconfig.h:
1078// struct ImGuiContext;
1079// extern thread_local ImGuiContext* MyImGuiTLS;
1080// #define GImGui MyImGuiTLS
1081// And then define MyImGuiTLS in one of your cpp files. Note that thread_local is a C++11 keyword, earlier C++ uses compiler-specific keyword.
1082// - Future development aims to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586
1083// - If you need a finite number of contexts, you may compile and use multiple instances of the ImGui code from a different namespace.
1084// - DLL users: read comments above.
1085#ifndef GImGui
1087#endif
1088
1089// Memory Allocator functions. Use SetAllocatorFunctions() to change them.
1090// - You probably don't want to modify that mid-program, and if you use global/static e.g. ImVector<> instances you may need to keep them accessible during program destruction.
1091// - DLL users: read comments above.
1092#ifndef IMGUI_DISABLE_DEFAULT_ALLOCATORS
1093static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); return malloc(size); }
1094static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); free(ptr); }
1095#else
1096static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(size); IM_ASSERT(0); return NULL; }
1097static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(ptr); IM_ASSERT(0); }
1098#endif
1099static ImGuiMemAllocFunc GImAllocatorAllocFunc = MallocWrapper;
1100static ImGuiMemFreeFunc GImAllocatorFreeFunc = FreeWrapper;
1101static void* GImAllocatorUserData = NULL;
1102
1103//-----------------------------------------------------------------------------
1104// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO)
1105//-----------------------------------------------------------------------------
1106
1108{
1109 Alpha = 1.0f; // Global alpha applies to everything in Dear ImGui.
1110 DisabledAlpha = 0.60f; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha.
1111 WindowPadding = ImVec2(8,8); // Padding within a window
1112 WindowRounding = 0.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended.
1113 WindowBorderSize = 1.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested.
1114 WindowMinSize = ImVec2(32,32); // Minimum window size
1115 WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text
1116 WindowMenuButtonPosition= ImGuiDir_Left; // Position of the collapsing/docking button in the title bar (left/right). Defaults to ImGuiDir_Left.
1117 ChildRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows
1118 ChildBorderSize = 1.0f; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested.
1119 PopupRounding = 0.0f; // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows
1120 PopupBorderSize = 1.0f; // Thickness of border around popup or tooltip windows. Generally set to 0.0f or 1.0f. Other values not well tested.
1121 FramePadding = ImVec2(4,3); // Padding within a framed rectangle (used by most widgets)
1122 FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets).
1123 FrameBorderSize = 0.0f; // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested.
1124 ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines
1125 ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label)
1126 CellPadding = ImVec2(4,2); // Padding within a table cell
1127 TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much!
1128 IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).
1129 ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1).
1130 ScrollbarSize = 14.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar
1131 ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar
1132 GrabMinSize = 12.0f; // Minimum width/height of a grab box for slider/scrollbar
1133 GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
1134 LogSliderDeadzone = 4.0f; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero.
1135 TabRounding = 4.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
1136 TabBorderSize = 0.0f; // Thickness of border around tabs.
1137 TabMinWidthForCloseButton = 0.0f; // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected.
1138 ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
1139 ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text.
1140 SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line.
1141 SeparatorTextBorderSize = 3.0f; // Thickkness of border in SeparatorText()
1142 SeparatorTextAlign = ImVec2(0.0f,0.5f);// Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center).
1143 SeparatorTextPadding = ImVec2(20.0f,3.f);// Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y.
1144 DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows.
1145 DisplaySafeAreaPadding = ImVec2(3,3); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows.
1146 MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
1147 AntiAliasedLines = true; // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU.
1148 AntiAliasedLinesUseTex = true; // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering (NOT point/nearest filtering).
1149 AntiAliasedFill = true; // Enable anti-aliased filled shapes (rounded rectangles, circles, etc.).
1150 CurveTessellationTol = 1.25f; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.
1151 CircleTessellationMaxError = 0.30f; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry.
1152
1153 // Default theme
1155}
1156
1157// To scale your entire UI (e.g. if you want your app to use High DPI or generally be DPI aware) you may use this helper function. Scaling the fonts is done separately and is up to you.
1158// Important: This operation is lossy because we round all sizes to integer. If you need to change your scale multiples, call this over a freshly initialized ImGuiStyle structure rather than scaling multiple times.
1159void ImGuiStyle::ScaleAllSizes(float scale_factor)
1160{
1161 WindowPadding = ImFloor(WindowPadding * scale_factor);
1162 WindowRounding = ImFloor(WindowRounding * scale_factor);
1163 WindowMinSize = ImFloor(WindowMinSize * scale_factor);
1164 ChildRounding = ImFloor(ChildRounding * scale_factor);
1165 PopupRounding = ImFloor(PopupRounding * scale_factor);
1166 FramePadding = ImFloor(FramePadding * scale_factor);
1167 FrameRounding = ImFloor(FrameRounding * scale_factor);
1168 ItemSpacing = ImFloor(ItemSpacing * scale_factor);
1169 ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor);
1170 CellPadding = ImFloor(CellPadding * scale_factor);
1171 TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor);
1172 IndentSpacing = ImFloor(IndentSpacing * scale_factor);
1173 ColumnsMinSpacing = ImFloor(ColumnsMinSpacing * scale_factor);
1174 ScrollbarSize = ImFloor(ScrollbarSize * scale_factor);
1175 ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor);
1176 GrabMinSize = ImFloor(GrabMinSize * scale_factor);
1177 GrabRounding = ImFloor(GrabRounding * scale_factor);
1178 LogSliderDeadzone = ImFloor(LogSliderDeadzone * scale_factor);
1179 TabRounding = ImFloor(TabRounding * scale_factor);
1180 TabMinWidthForCloseButton = (TabMinWidthForCloseButton != FLT_MAX) ? ImFloor(TabMinWidthForCloseButton * scale_factor) : FLT_MAX;
1181 SeparatorTextPadding = ImFloor(SeparatorTextPadding * scale_factor);
1182 DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor);
1183 DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor);
1184 MouseCursorScale = ImFloor(MouseCursorScale * scale_factor);
1185}
1186
1188{
1189 // Most fields are initialized with zero
1190 memset(this, 0, sizeof(*this));
1192
1193 // Settings
1196 DisplaySize = ImVec2(-1.0f, -1.0f);
1197 DeltaTime = 1.0f / 60.0f;
1198 IniSavingRate = 5.0f;
1199 IniFilename = "imgui.ini"; // Important: "imgui.ini" is relative to current working dir, most apps will want to lock this to an absolute path (e.g. same path as executables).
1200 LogFilename = "imgui_log.txt";
1201 MouseDoubleClickTime = 0.30f;
1203#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
1204 for (int i = 0; i < ImGuiKey_COUNT; i++)
1205 KeyMap[i] = -1;
1206#endif
1207 KeyRepeatDelay = 0.275f;
1208 KeyRepeatRate = 0.050f;
1209 HoverDelayNormal = 0.30f;
1210 HoverDelayShort = 0.10f;
1211 UserData = NULL;
1212
1213 Fonts = NULL;
1214 FontGlobalScale = 1.0f;
1215 FontDefault = NULL;
1216 FontAllowUserScaling = false;
1217 DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
1218
1219 // Miscellaneous options
1220 MouseDrawCursor = false;
1221#ifdef __APPLE__
1222 ConfigMacOSXBehaviors = true; // Set Mac OS X style defaults based on __APPLE__ compile time flag
1223#else
1224 ConfigMacOSXBehaviors = false;
1225#endif
1233
1234 // Platform Functions
1235 // Note: Initialize() will setup default clipboard/ime handlers.
1238
1239 // Input (NB: we already have memset zero the entire structure!)
1240 MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
1241 MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX);
1242 MouseDragThreshold = 6.0f;
1243 for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f;
1244 for (int i = 0; i < IM_ARRAYSIZE(KeysData); i++) { KeysData[i].DownDuration = KeysData[i].DownDurationPrev = -1.0f; }
1245 AppAcceptingEvents = true;
1247 BackendUsingLegacyNavInputArray = true; // assume using legacy array until proven wrong
1248}
1249
1250// Pass in translated ASCII characters for text input.
1251// - with glfw you can get those from the callback set in glfwSetCharCallback()
1252// - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message
1253// FIXME: Should in theory be called "AddCharacterEvent()" to be consistent with new API
1254void ImGuiIO::AddInputCharacter(unsigned int c)
1255{
1256 IM_ASSERT(Ctx != NULL);
1257 ImGuiContext& g = *Ctx;
1258 if (c == 0 || !AppAcceptingEvents)
1259 return;
1260
1264 e.Text.Char = c;
1266}
1267
1268// UTF16 strings use surrogate pairs to encode codepoints >= 0x10000, so
1269// we should save the high surrogate.
1271{
1272 if ((c == 0 && InputQueueSurrogate == 0) || !AppAcceptingEvents)
1273 return;
1274
1275 if ((c & 0xFC00) == 0xD800) // High surrogate, must save
1276 {
1277 if (InputQueueSurrogate != 0)
1280 return;
1281 }
1282
1283 ImWchar cp = c;
1284 if (InputQueueSurrogate != 0)
1285 {
1286 if ((c & 0xFC00) != 0xDC00) // Invalid low surrogate
1287 {
1289 }
1290 else
1291 {
1292#if IM_UNICODE_CODEPOINT_MAX == 0xFFFF
1293 cp = IM_UNICODE_CODEPOINT_INVALID; // Codepoint will not fit in ImWchar
1294#else
1295 cp = (ImWchar)(((InputQueueSurrogate - 0xD800) << 10) + (c - 0xDC00) + 0x10000);
1296#endif
1297 }
1298
1300 }
1301 AddInputCharacter((unsigned)cp);
1302}
1303
1304void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
1305{
1306 if (!AppAcceptingEvents)
1307 return;
1308 while (*utf8_chars != 0)
1309 {
1310 unsigned int c = 0;
1311 utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL);
1313 }
1314}
1315
1316// FIXME: Perhaps we could clear queued events as well?
1321
1322// FIXME: Perhaps we could clear queued events as well?
1324{
1325#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
1326 memset(KeysDown, 0, sizeof(KeysDown));
1327#endif
1328 for (int n = 0; n < IM_ARRAYSIZE(KeysData); n++)
1329 {
1330 KeysData[n].Down = false;
1331 KeysData[n].DownDuration = -1.0f;
1332 KeysData[n].DownDurationPrev = -1.0f;
1333 }
1334 KeyCtrl = KeyShift = KeyAlt = KeySuper = false;
1336 MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
1337 for (int n = 0; n < IM_ARRAYSIZE(MouseDown); n++)
1338 {
1339 MouseDown[n] = false;
1341 }
1342 MouseWheel = MouseWheelH = 0.0f;
1343}
1344
1345static ImGuiInputEvent* FindLatestInputEvent(ImGuiInputEventType type, int arg = -1)
1346{
1347 ImGuiContext& g = *GImGui;
1348 for (int n = g.InputEventsQueue.Size - 1; n >= 0; n--)
1349 {
1351 if (e->Type != type)
1352 continue;
1353 if (type == ImGuiInputEventType_Key && e->Key.Key != arg)
1354 continue;
1355 if (type == ImGuiInputEventType_MouseButton && e->MouseButton.Button != arg)
1356 continue;
1357 return e;
1358 }
1359 return NULL;
1360}
1361
1362// Queue a new key down/up event.
1363// - ImGuiKey key: Translated key (as in, generally ImGuiKey_A matches the key end-user would use to emit an 'A' character)
1364// - bool down: Is the key down? use false to signify a key release.
1365// - float analog_value: 0.0f..1.0f
1366void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value)
1367{
1368 //if (e->Down) { IMGUI_DEBUG_LOG_IO("AddKeyEvent() Key='%s' %d, NativeKeycode = %d, NativeScancode = %d\n", ImGui::GetKeyName(e->Key), e->Down, e->NativeKeycode, e->NativeScancode); }
1369 IM_ASSERT(Ctx != NULL);
1370 if (key == ImGuiKey_None || !AppAcceptingEvents)
1371 return;
1372 ImGuiContext& g = *Ctx;
1373 IM_ASSERT(ImGui::IsNamedKeyOrModKey(key)); // Backend needs to pass a valid ImGuiKey_ constant. 0..511 values are legacy native key codes which are not accepted by this API.
1374 IM_ASSERT(!ImGui::IsAliasKey(key)); // Backend cannot submit ImGuiKey_MouseXXX values they are automatically inferred from AddMouseXXX() events.
1375 IM_ASSERT(key != ImGuiMod_Shortcut); // We could easily support the translation here but it seems saner to not accept it (TestEngine perform a translation itself)
1376
1377 // Verify that backend isn't mixing up using new io.AddKeyEvent() api and old io.KeysDown[] + io.KeyMap[] data.
1378#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
1379 IM_ASSERT((BackendUsingLegacyKeyArrays == -1 || BackendUsingLegacyKeyArrays == 0) && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!");
1381 for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_NamedKey_END; n++)
1382 IM_ASSERT(KeyMap[n] == -1 && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!");
1384#endif
1385 if (ImGui::IsGamepadKey(key))
1387
1388 // Filter duplicate (in particular: key mods and gamepad analog values are commonly spammed)
1389 const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_Key, (int)key);
1390 const ImGuiKeyData* key_data = ImGui::GetKeyData(key);
1391 const bool latest_key_down = latest_event ? latest_event->Key.Down : key_data->Down;
1392 const float latest_key_analog = latest_event ? latest_event->Key.AnalogValue : key_data->AnalogValue;
1393 if (latest_key_down == down && latest_key_analog == analog_value)
1394 return;
1395
1396 // Add event
1400 e.Key.Key = key;
1401 e.Key.Down = down;
1402 e.Key.AnalogValue = analog_value;
1404}
1405
1406void ImGuiIO::AddKeyEvent(ImGuiKey key, bool down)
1407{
1408 if (!AppAcceptingEvents)
1409 return;
1410 AddKeyAnalogEvent(key, down, down ? 1.0f : 0.0f);
1411}
1412
1413// [Optional] Call after AddKeyEvent().
1414// Specify native keycode, scancode + Specify index for legacy <1.87 IsKeyXXX() functions with native indices.
1415// If you are writing a backend in 2022 or don't use IsKeyXXX() with native values that are not ImGuiKey values, you can avoid calling this.
1416void ImGuiIO::SetKeyEventNativeData(ImGuiKey key, int native_keycode, int native_scancode, int native_legacy_index)
1417{
1418 if (key == ImGuiKey_None)
1419 return;
1420 IM_ASSERT(ImGui::IsNamedKey(key)); // >= 512
1421 IM_ASSERT(native_legacy_index == -1 || ImGui::IsLegacyKey((ImGuiKey)native_legacy_index)); // >= 0 && <= 511
1422 IM_UNUSED(native_keycode); // Yet unused
1423 IM_UNUSED(native_scancode); // Yet unused
1424
1425 // Build native->imgui map so old user code can still call key functions with native 0..511 values.
1426#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
1427 const int legacy_key = (native_legacy_index != -1) ? native_legacy_index : native_keycode;
1428 if (!ImGui::IsLegacyKey((ImGuiKey)legacy_key))
1429 return;
1430 KeyMap[legacy_key] = key;
1431 KeyMap[key] = legacy_key;
1432#else
1433 IM_UNUSED(key);
1434 IM_UNUSED(native_legacy_index);
1435#endif
1436}
1437
1438// Set master flag for accepting key/mouse/text events (default to true). Useful if you have native dialog boxes that are interrupting your application loop/refresh, and you want to disable events being queued while your app is frozen.
1439void ImGuiIO::SetAppAcceptingEvents(bool accepting_events)
1440{
1441 AppAcceptingEvents = accepting_events;
1442}
1443
1444// Queue a mouse move event
1445void ImGuiIO::AddMousePosEvent(float x, float y)
1446{
1447 IM_ASSERT(Ctx != NULL);
1448 ImGuiContext& g = *Ctx;
1449 if (!AppAcceptingEvents)
1450 return;
1451
1452 // Apply same flooring as UpdateMouseInputs()
1453 ImVec2 pos((x > -FLT_MAX) ? ImFloorSigned(x) : x, (y > -FLT_MAX) ? ImFloorSigned(y) : y);
1454
1455 // Filter duplicate
1456 const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_MousePos);
1457 const ImVec2 latest_pos = latest_event ? ImVec2(latest_event->MousePos.PosX, latest_event->MousePos.PosY) : g.IO.MousePos;
1458 if (latest_pos.x == pos.x && latest_pos.y == pos.y)
1459 return;
1460
1464 e.MousePos.PosX = pos.x;
1465 e.MousePos.PosY = pos.y;
1467}
1468
1469void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down)
1470{
1471 IM_ASSERT(Ctx != NULL);
1472 ImGuiContext& g = *Ctx;
1473 IM_ASSERT(mouse_button >= 0 && mouse_button < ImGuiMouseButton_COUNT);
1474 if (!AppAcceptingEvents)
1475 return;
1476
1477 // Filter duplicate
1478 const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_MouseButton, (int)mouse_button);
1479 const bool latest_button_down = latest_event ? latest_event->MouseButton.Down : g.IO.MouseDown[mouse_button];
1480 if (latest_button_down == down)
1481 return;
1482
1486 e.MouseButton.Button = mouse_button;
1487 e.MouseButton.Down = down;
1489}
1490
1491// Queue a mouse wheel event (some mouse/API may only have a Y component)
1492void ImGuiIO::AddMouseWheelEvent(float wheel_x, float wheel_y)
1493{
1494 IM_ASSERT(Ctx != NULL);
1495 ImGuiContext& g = *Ctx;
1496
1497 // Filter duplicate (unlike most events, wheel values are relative and easy to filter)
1498 if (!AppAcceptingEvents || (wheel_x == 0.0f && wheel_y == 0.0f))
1499 return;
1500
1504 e.MouseWheel.WheelX = wheel_x;
1505 e.MouseWheel.WheelY = wheel_y;
1507}
1508
1509void ImGuiIO::AddFocusEvent(bool focused)
1510{
1511 IM_ASSERT(Ctx != NULL);
1512 ImGuiContext& g = *Ctx;
1513
1514 // Filter duplicate
1515 const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_Focus);
1516 const bool latest_focused = latest_event ? latest_event->AppFocused.Focused : !g.IO.AppFocusLost;
1517 if (latest_focused == focused)
1518 return;
1519
1522 e.AppFocused.Focused = focused;
1524}
1525
1526//-----------------------------------------------------------------------------
1527// [SECTION] MISC HELPERS/UTILITIES (Geometry functions)
1528//-----------------------------------------------------------------------------
1529
1530ImVec2 ImBezierCubicClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments)
1531{
1532 IM_ASSERT(num_segments > 0); // Use ImBezierCubicClosestPointCasteljau()
1533 ImVec2 p_last = p1;
1534 ImVec2 p_closest;
1535 float p_closest_dist2 = FLT_MAX;
1536 float t_step = 1.0f / (float)num_segments;
1537 for (int i_step = 1; i_step <= num_segments; i_step++)
1538 {
1539 ImVec2 p_current = ImBezierCubicCalc(p1, p2, p3, p4, t_step * i_step);
1540 ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p);
1541 float dist2 = ImLengthSqr(p - p_line);
1542 if (dist2 < p_closest_dist2)
1543 {
1544 p_closest = p_line;
1545 p_closest_dist2 = dist2;
1546 }
1547 p_last = p_current;
1548 }
1549 return p_closest;
1550}
1551
1552// Closely mimics PathBezierToCasteljau() in imgui_draw.cpp
1553static void ImBezierCubicClosestPointCasteljauStep(const ImVec2& p, ImVec2& p_closest, ImVec2& p_last, float& p_closest_dist2, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level)
1554{
1555 float dx = x4 - x1;
1556 float dy = y4 - y1;
1557 float d2 = ((x2 - x4) * dy - (y2 - y4) * dx);
1558 float d3 = ((x3 - x4) * dy - (y3 - y4) * dx);
1559 d2 = (d2 >= 0) ? d2 : -d2;
1560 d3 = (d3 >= 0) ? d3 : -d3;
1561 if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy))
1562 {
1563 ImVec2 p_current(x4, y4);
1564 ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p);
1565 float dist2 = ImLengthSqr(p - p_line);
1566 if (dist2 < p_closest_dist2)
1567 {
1568 p_closest = p_line;
1569 p_closest_dist2 = dist2;
1570 }
1571 p_last = p_current;
1572 }
1573 else if (level < 10)
1574 {
1575 float x12 = (x1 + x2)*0.5f, y12 = (y1 + y2)*0.5f;
1576 float x23 = (x2 + x3)*0.5f, y23 = (y2 + y3)*0.5f;
1577 float x34 = (x3 + x4)*0.5f, y34 = (y3 + y4)*0.5f;
1578 float x123 = (x12 + x23)*0.5f, y123 = (y12 + y23)*0.5f;
1579 float x234 = (x23 + x34)*0.5f, y234 = (y23 + y34)*0.5f;
1580 float x1234 = (x123 + x234)*0.5f, y1234 = (y123 + y234)*0.5f;
1581 ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);
1582 ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);
1583 }
1584}
1585
1586// tess_tol is generally the same value you would find in ImGui::GetStyle().CurveTessellationTol
1587// Because those ImXXX functions are lower-level than ImGui:: we cannot access this value automatically.
1588ImVec2 ImBezierCubicClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol)
1589{
1590 IM_ASSERT(tess_tol > 0.0f);
1591 ImVec2 p_last = p1;
1592 ImVec2 p_closest;
1593 float p_closest_dist2 = FLT_MAX;
1594 ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, tess_tol, 0);
1595 return p_closest;
1596}
1597
1598ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p)
1599{
1600 ImVec2 ap = p - a;
1601 ImVec2 ab_dir = b - a;
1602 float dot = ap.x * ab_dir.x + ap.y * ab_dir.y;
1603 if (dot < 0.0f)
1604 return a;
1605 float ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y;
1606 if (dot > ab_len_sqr)
1607 return b;
1608 return a + ab_dir * dot / ab_len_sqr;
1609}
1610
1611bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
1612{
1613 bool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f;
1614 bool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f;
1615 bool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f;
1616 return ((b1 == b2) && (b2 == b3));
1617}
1618
1619void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w)
1620{
1621 ImVec2 v0 = b - a;
1622 ImVec2 v1 = c - a;
1623 ImVec2 v2 = p - a;
1624 const float denom = v0.x * v1.y - v1.x * v0.y;
1625 out_v = (v2.x * v1.y - v1.x * v2.y) / denom;
1626 out_w = (v0.x * v2.y - v2.x * v0.y) / denom;
1627 out_u = 1.0f - out_v - out_w;
1628}
1629
1630ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
1631{
1632 ImVec2 proj_ab = ImLineClosestPoint(a, b, p);
1633 ImVec2 proj_bc = ImLineClosestPoint(b, c, p);
1634 ImVec2 proj_ca = ImLineClosestPoint(c, a, p);
1635 float dist2_ab = ImLengthSqr(p - proj_ab);
1636 float dist2_bc = ImLengthSqr(p - proj_bc);
1637 float dist2_ca = ImLengthSqr(p - proj_ca);
1638 float m = ImMin(dist2_ab, ImMin(dist2_bc, dist2_ca));
1639 if (m == dist2_ab)
1640 return proj_ab;
1641 if (m == dist2_bc)
1642 return proj_bc;
1643 return proj_ca;
1644}
1645
1646//-----------------------------------------------------------------------------
1647// [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions)
1648//-----------------------------------------------------------------------------
1649
1650// Consider using _stricmp/_strnicmp under Windows or strcasecmp/strncasecmp. We don't actually use either ImStricmp/ImStrnicmp in the codebase any more.
1651int ImStricmp(const char* str1, const char* str2)
1652{
1653 int d;
1654 while ((d = ImToUpper(*str2) - ImToUpper(*str1)) == 0 && *str1) { str1++; str2++; }
1655 return d;
1656}
1657
1658int ImStrnicmp(const char* str1, const char* str2, size_t count)
1659{
1660 int d = 0;
1661 while (count > 0 && (d = ImToUpper(*str2) - ImToUpper(*str1)) == 0 && *str1) { str1++; str2++; count--; }
1662 return d;
1663}
1664
1665void ImStrncpy(char* dst, const char* src, size_t count)
1666{
1667 if (count < 1)
1668 return;
1669 if (count > 1)
1670 strncpy(dst, src, count - 1);
1671 dst[count - 1] = 0;
1672}
1673
1674char* ImStrdup(const char* str)
1675{
1676 size_t len = strlen(str);
1677 void* buf = IM_ALLOC(len + 1);
1678 return (char*)memcpy(buf, (const void*)str, len + 1);
1679}
1680
1681char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* src)
1682{
1683 size_t dst_buf_size = p_dst_size ? *p_dst_size : strlen(dst) + 1;
1684 size_t src_size = strlen(src) + 1;
1685 if (dst_buf_size < src_size)
1686 {
1687 IM_FREE(dst);
1688 dst = (char*)IM_ALLOC(src_size);
1689 if (p_dst_size)
1690 *p_dst_size = src_size;
1691 }
1692 return (char*)memcpy(dst, (const void*)src, src_size);
1693}
1694
1695const char* ImStrchrRange(const char* str, const char* str_end, char c)
1696{
1697 const char* p = (const char*)memchr(str, (int)c, str_end - str);
1698 return p;
1699}
1700
1701int ImStrlenW(const ImWchar* str)
1702{
1703 //return (int)wcslen((const wchar_t*)str); // FIXME-OPT: Could use this when wchar_t are 16-bit
1704 int n = 0;
1705 while (*str++) n++;
1706 return n;
1707}
1708
1709// Find end-of-line. Return pointer will point to either first \n, either str_end.
1710const char* ImStreolRange(const char* str, const char* str_end)
1711{
1712 const char* p = (const char*)memchr(str, '\n', str_end - str);
1713 return p ? p : str_end;
1714}
1715
1716const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin) // find beginning-of-line
1717{
1718 while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n')
1719 buf_mid_line--;
1720 return buf_mid_line;
1721}
1722
1723const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end)
1724{
1725 if (!needle_end)
1726 needle_end = needle + strlen(needle);
1727
1728 const char un0 = (char)ImToUpper(*needle);
1729 while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end))
1730 {
1731 if (ImToUpper(*haystack) == un0)
1732 {
1733 const char* b = needle + 1;
1734 for (const char* a = haystack + 1; b < needle_end; a++, b++)
1735 if (ImToUpper(*a) != ImToUpper(*b))
1736 break;
1737 if (b == needle_end)
1738 return haystack;
1739 }
1740 haystack++;
1741 }
1742 return NULL;
1743}
1744
1745// Trim str by offsetting contents when there's leading data + writing a \0 at the trailing position. We use this in situation where the cost is negligible.
1746void ImStrTrimBlanks(char* buf)
1747{
1748 char* p = buf;
1749 while (p[0] == ' ' || p[0] == '\t') // Leading blanks
1750 p++;
1751 char* p_start = p;
1752 while (*p != 0) // Find end of string
1753 p++;
1754 while (p > p_start && (p[-1] == ' ' || p[-1] == '\t')) // Trailing blanks
1755 p--;
1756 if (p_start != buf) // Copy memory if we had leading blanks
1757 memmove(buf, p_start, p - p_start);
1758 buf[p - p_start] = 0; // Zero terminate
1759}
1760
1761const char* ImStrSkipBlank(const char* str)
1762{
1763 while (str[0] == ' ' || str[0] == '\t')
1764 str++;
1765 return str;
1766}
1767
1768// A) MSVC version appears to return -1 on overflow, whereas glibc appears to return total count (which may be >= buf_size).
1769// Ideally we would test for only one of those limits at runtime depending on the behavior the vsnprintf(), but trying to deduct it at compile time sounds like a pandora can of worm.
1770// B) When buf==NULL vsnprintf() will return the output size.
1771#ifndef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
1772
1773// We support stb_sprintf which is much faster (see: https://github.com/nothings/stb/blob/master/stb_sprintf.h)
1774// You may set IMGUI_USE_STB_SPRINTF to use our default wrapper, or set IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
1775// and setup the wrapper yourself. (FIXME-OPT: Some of our high-level operations such as ImGuiTextBuffer::appendfv() are
1776// designed using two-passes worst case, which probably could be improved using the stbsp_vsprintfcb() function.)
1777#ifdef IMGUI_USE_STB_SPRINTF
1778#define STB_SPRINTF_IMPLEMENTATION
1779#ifdef IMGUI_STB_SPRINTF_FILENAME
1780#include IMGUI_STB_SPRINTF_FILENAME
1781#else
1782#include "stb_sprintf.h"
1783#endif
1784#endif
1785
1786#if defined(_MSC_VER) && !defined(vsnprintf)
1787#define vsnprintf _vsnprintf
1788#endif
1789
1790int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...)
1791{
1792 va_list args;
1793 va_start(args, fmt);
1794#ifdef IMGUI_USE_STB_SPRINTF
1795 int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args);
1796#else
1797 int w = vsnprintf(buf, buf_size, fmt, args);
1798#endif
1799 va_end(args);
1800 if (buf == NULL)
1801 return w;
1802 if (w == -1 || w >= (int)buf_size)
1803 w = (int)buf_size - 1;
1804 buf[w] = 0;
1805 return w;
1806}
1807
1808int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args)
1809{
1810#ifdef IMGUI_USE_STB_SPRINTF
1811 int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args);
1812#else
1813 int w = vsnprintf(buf, buf_size, fmt, args);
1814#endif
1815 if (buf == NULL)
1816 return w;
1817 if (w == -1 || w >= (int)buf_size)
1818 w = (int)buf_size - 1;
1819 buf[w] = 0;
1820 return w;
1821}
1822#endif // #ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
1823
1824void ImFormatStringToTempBuffer(const char** out_buf, const char** out_buf_end, const char* fmt, ...)
1825{
1826 ImGuiContext& g = *GImGui;
1827 va_list args;
1828 va_start(args, fmt);
1829 if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0)
1830 {
1831 const char* buf = va_arg(args, const char*); // Skip formatting when using "%s"
1832 *out_buf = buf;
1833 if (out_buf_end) { *out_buf_end = buf + strlen(buf); }
1834 }
1835 else
1836 {
1837 int buf_len = ImFormatStringV(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args);
1838 *out_buf = g.TempBuffer.Data;
1839 if (out_buf_end) { *out_buf_end = g.TempBuffer.Data + buf_len; }
1840 }
1841 va_end(args);
1842}
1843
1844void ImFormatStringToTempBufferV(const char** out_buf, const char** out_buf_end, const char* fmt, va_list args)
1845{
1846 ImGuiContext& g = *GImGui;
1847 if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0)
1848 {
1849 const char* buf = va_arg(args, const char*); // Skip formatting when using "%s"
1850 *out_buf = buf;
1851 if (out_buf_end) { *out_buf_end = buf + strlen(buf); }
1852 }
1853 else
1854 {
1855 int buf_len = ImFormatStringV(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args);
1856 *out_buf = g.TempBuffer.Data;
1857 if (out_buf_end) { *out_buf_end = g.TempBuffer.Data + buf_len; }
1858 }
1859}
1860
1861// CRC32 needs a 1KB lookup table (not cache friendly)
1862// Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily:
1863// - avoid an unnecessary branch/memory tap, - keep the ImHashXXX functions usable by static constructors, - make it thread-safe.
1864static const ImU32 GCrc32LookupTable[256] =
1865{
1866 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91,
1867 0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5,
1868 0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,
1869 0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D,
1870 0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01,
1871 0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,
1872 0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9,
1873 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD,
1874 0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,
1875 0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,
1876 0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79,
1877 0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,
1878 0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,
1879 0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45,
1880 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9,
1881 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D,
1882};
1883
1884// Known size hash
1885// It is ok to call ImHashData on a string with known length but the ### operator won't be supported.
1886// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
1887ImGuiID ImHashData(const void* data_p, size_t data_size, ImGuiID seed)
1888{
1889 ImU32 crc = ~seed;
1890 const unsigned char* data = (const unsigned char*)data_p;
1891 const ImU32* crc32_lut = GCrc32LookupTable;
1892 while (data_size-- != 0)
1893 crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *data++];
1894 return ~crc;
1895}
1896
1897// Zero-terminated string hash, with support for ### to reset back to seed value
1898// We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed.
1899// Because this syntax is rarely used we are optimizing for the common case.
1900// - If we reach ### in the string we discard the hash so far and reset to the seed.
1901// - We don't do 'current += 2; continue;' after handling ### to keep the code smaller/faster (measured ~10% diff in Debug build)
1902// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
1903ImGuiID ImHashStr(const char* data_p, size_t data_size, ImGuiID seed)
1904{
1905 seed = ~seed;
1906 ImU32 crc = seed;
1907 const unsigned char* data = (const unsigned char*)data_p;
1908 const ImU32* crc32_lut = GCrc32LookupTable;
1909 if (data_size != 0)
1910 {
1911 while (data_size-- != 0)
1912 {
1913 unsigned char c = *data++;
1914 if (c == '#' && data_size >= 2 && data[0] == '#' && data[1] == '#')
1915 crc = seed;
1916 crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
1917 }
1918 }
1919 else
1920 {
1921 while (unsigned char c = *data++)
1922 {
1923 if (c == '#' && data[0] == '#' && data[1] == '#')
1924 crc = seed;
1925 crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
1926 }
1927 }
1928 return ~crc;
1929}
1930
1931//-----------------------------------------------------------------------------
1932// [SECTION] MISC HELPERS/UTILITIES (File functions)
1933//-----------------------------------------------------------------------------
1934
1935// Default file functions
1936#ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
1937
1938ImFileHandle ImFileOpen(const char* filename, const char* mode)
1939{
1940#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(__CYGWIN__) && !defined(__GNUC__)
1941 // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames.
1942 // Previously we used ImTextCountCharsFromUtf8/ImTextStrFromUtf8 here but we now need to support ImWchar16 and ImWchar32!
1943 const int filename_wsize = ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0);
1944 const int mode_wsize = ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0);
1946 buf.resize(filename_wsize + mode_wsize);
1947 ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, (wchar_t*)&buf[0], filename_wsize);
1948 ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, (wchar_t*)&buf[filename_wsize], mode_wsize);
1949 return ::_wfopen((const wchar_t*)&buf[0], (const wchar_t*)&buf[filename_wsize]);
1950#else
1951 return fopen(filename, mode);
1952#endif
1953}
1954
1955// We should in theory be using fseeko()/ftello() with off_t and _fseeki64()/_ftelli64() with __int64, waiting for the PR that does that in a very portable pre-C++11 zero-warnings way.
1956bool ImFileClose(ImFileHandle f) { return fclose(f) == 0; }
1957ImU64 ImFileGetSize(ImFileHandle f) { long off = 0, sz = 0; return ((off = ftell(f)) != -1 && !fseek(f, 0, SEEK_END) && (sz = ftell(f)) != -1 && !fseek(f, off, SEEK_SET)) ? (ImU64)sz : (ImU64)-1; }
1958ImU64 ImFileRead(void* data, ImU64 sz, ImU64 count, ImFileHandle f) { return fread(data, (size_t)sz, (size_t)count, f); }
1959ImU64 ImFileWrite(const void* data, ImU64 sz, ImU64 count, ImFileHandle f) { return fwrite(data, (size_t)sz, (size_t)count, f); }
1960#endif // #ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
1961
1962// Helper: Load file content into memory
1963// Memory allocated with IM_ALLOC(), must be freed by user using IM_FREE() == ImGui::MemFree()
1964// This can't really be used with "rt" because fseek size won't match read size.
1965void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size, int padding_bytes)
1966{
1967 IM_ASSERT(filename && mode);
1968 if (out_file_size)
1969 *out_file_size = 0;
1970
1971 ImFileHandle f;
1972 if ((f = ImFileOpen(filename, mode)) == NULL)
1973 return NULL;
1974
1975 size_t file_size = (size_t)ImFileGetSize(f);
1976 if (file_size == (size_t)-1)
1977 {
1978 ImFileClose(f);
1979 return NULL;
1980 }
1981
1982 void* file_data = IM_ALLOC(file_size + padding_bytes);
1983 if (file_data == NULL)
1984 {
1985 ImFileClose(f);
1986 return NULL;
1987 }
1988 if (ImFileRead(file_data, 1, file_size, f) != file_size)
1989 {
1990 ImFileClose(f);
1991 IM_FREE(file_data);
1992 return NULL;
1993 }
1994 if (padding_bytes > 0)
1995 memset((void*)(((char*)file_data) + file_size), 0, (size_t)padding_bytes);
1996
1997 ImFileClose(f);
1998 if (out_file_size)
1999 *out_file_size = file_size;
2000
2001 return file_data;
2002}
2003
2004//-----------------------------------------------------------------------------
2005// [SECTION] MISC HELPERS/UTILITIES (ImText* functions)
2006//-----------------------------------------------------------------------------
2007
2009
2010// Convert UTF-8 to 32-bit character, process single character input.
2011// A nearly-branchless UTF-8 decoder, based on work of Christopher Wellons (https://github.com/skeeto/branchless-utf8).
2012// We handle UTF-8 decoding error by skipping forward.
2013int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end)
2014{
2015 static const char lengths[32] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0 };
2016 static const int masks[] = { 0x00, 0x7f, 0x1f, 0x0f, 0x07 };
2017 static const uint32_t mins[] = { 0x400000, 0, 0x80, 0x800, 0x10000 };
2018 static const int shiftc[] = { 0, 18, 12, 6, 0 };
2019 static const int shifte[] = { 0, 6, 4, 2, 0 };
2020 int len = lengths[*(const unsigned char*)in_text >> 3];
2021 int wanted = len + (len ? 0 : 1);
2022
2023 if (in_text_end == NULL)
2024 in_text_end = in_text + wanted; // Max length, nulls will be taken into account.
2025
2026 // Copy at most 'len' bytes, stop copying at 0 or past in_text_end. Branch predictor does a good job here,
2027 // so it is fast even with excessive branching.
2028 unsigned char s[4];
2029 s[0] = in_text + 0 < in_text_end ? in_text[0] : 0;
2030 s[1] = in_text + 1 < in_text_end ? in_text[1] : 0;
2031 s[2] = in_text + 2 < in_text_end ? in_text[2] : 0;
2032 s[3] = in_text + 3 < in_text_end ? in_text[3] : 0;
2033
2034 // Assume a four-byte character and load four bytes. Unused bits are shifted out.
2035 *out_char = (uint32_t)(s[0] & masks[len]) << 18;
2036 *out_char |= (uint32_t)(s[1] & 0x3f) << 12;
2037 *out_char |= (uint32_t)(s[2] & 0x3f) << 6;
2038 *out_char |= (uint32_t)(s[3] & 0x3f) << 0;
2039 *out_char >>= shiftc[len];
2040
2041 // Accumulate the various error conditions.
2042 int e = 0;
2043 e = (*out_char < mins[len]) << 6; // non-canonical encoding
2044 e |= ((*out_char >> 11) == 0x1b) << 7; // surrogate half?
2045 e |= (*out_char > IM_UNICODE_CODEPOINT_MAX) << 8; // out of range?
2046 e |= (s[1] & 0xc0) >> 2;
2047 e |= (s[2] & 0xc0) >> 4;
2048 e |= (s[3] ) >> 6;
2049 e ^= 0x2a; // top two bits of each tail byte correct?
2050 e >>= shifte[len];
2051
2052 if (e)
2053 {
2054 // No bytes are consumed when *in_text == 0 || in_text == in_text_end.
2055 // One byte is consumed in case of invalid first byte of in_text.
2056 // All available bytes (at most `len` bytes) are consumed on incomplete/invalid second to last bytes.
2057 // Invalid or incomplete input may consume less bytes than wanted, therefore every byte has to be inspected in s.
2058 wanted = ImMin(wanted, !!s[0] + !!s[1] + !!s[2] + !!s[3]);
2059 *out_char = IM_UNICODE_CODEPOINT_INVALID;
2060 }
2061
2062 return wanted;
2063}
2064
2065int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining)
2066{
2067 ImWchar* buf_out = buf;
2068 ImWchar* buf_end = buf + buf_size;
2069 while (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text)
2070 {
2071 unsigned int c;
2072 in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
2073 *buf_out++ = (ImWchar)c;
2074 }
2075 *buf_out = 0;
2076 if (in_text_remaining)
2077 *in_text_remaining = in_text;
2078 return (int)(buf_out - buf);
2079}
2080
2081int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end)
2082{
2083 int char_count = 0;
2084 while ((!in_text_end || in_text < in_text_end) && *in_text)
2085 {
2086 unsigned int c;
2087 in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
2088 char_count++;
2089 }
2090 return char_count;
2091}
2092
2093// Based on stb_to_utf8() from github.com/nothings/stb/
2094static inline int ImTextCharToUtf8_inline(char* buf, int buf_size, unsigned int c)
2095{
2096 if (c < 0x80)
2097 {
2098 buf[0] = (char)c;
2099 return 1;
2100 }
2101 if (c < 0x800)
2102 {
2103 if (buf_size < 2) return 0;
2104 buf[0] = (char)(0xc0 + (c >> 6));
2105 buf[1] = (char)(0x80 + (c & 0x3f));
2106 return 2;
2107 }
2108 if (c < 0x10000)
2109 {
2110 if (buf_size < 3) return 0;
2111 buf[0] = (char)(0xe0 + (c >> 12));
2112 buf[1] = (char)(0x80 + ((c >> 6) & 0x3f));
2113 buf[2] = (char)(0x80 + ((c ) & 0x3f));
2114 return 3;
2115 }
2116 if (c <= 0x10FFFF)
2117 {
2118 if (buf_size < 4) return 0;
2119 buf[0] = (char)(0xf0 + (c >> 18));
2120 buf[1] = (char)(0x80 + ((c >> 12) & 0x3f));
2121 buf[2] = (char)(0x80 + ((c >> 6) & 0x3f));
2122 buf[3] = (char)(0x80 + ((c ) & 0x3f));
2123 return 4;
2124 }
2125 // Invalid code point, the max unicode is 0x10FFFF
2126 return 0;
2127}
2128
2129const char* ImTextCharToUtf8(char out_buf[5], unsigned int c)
2130{
2131 int count = ImTextCharToUtf8_inline(out_buf, 5, c);
2132 out_buf[count] = 0;
2133 return out_buf;
2134}
2135
2136// Not optimal but we very rarely use this function.
2137int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end)
2138{
2139 unsigned int unused = 0;
2140 return ImTextCharFromUtf8(&unused, in_text, in_text_end);
2141}
2142
2143static inline int ImTextCountUtf8BytesFromChar(unsigned int c)
2144{
2145 if (c < 0x80) return 1;
2146 if (c < 0x800) return 2;
2147 if (c < 0x10000) return 3;
2148 if (c <= 0x10FFFF) return 4;
2149 return 3;
2150}
2151
2152int ImTextStrToUtf8(char* out_buf, int out_buf_size, const ImWchar* in_text, const ImWchar* in_text_end)
2153{
2154 char* buf_p = out_buf;
2155 const char* buf_end = out_buf + out_buf_size;
2156 while (buf_p < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text)
2157 {
2158 unsigned int c = (unsigned int)(*in_text++);
2159 if (c < 0x80)
2160 *buf_p++ = (char)c;
2161 else
2162 buf_p += ImTextCharToUtf8_inline(buf_p, (int)(buf_end - buf_p - 1), c);
2163 }
2164 *buf_p = 0;
2165 return (int)(buf_p - out_buf);
2166}
2167
2168int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end)
2169{
2170 int bytes_count = 0;
2171 while ((!in_text_end || in_text < in_text_end) && *in_text)
2172 {
2173 unsigned int c = (unsigned int)(*in_text++);
2174 if (c < 0x80)
2175 bytes_count++;
2176 else
2177 bytes_count += ImTextCountUtf8BytesFromChar(c);
2178 }
2179 return bytes_count;
2180}
2182
2183//-----------------------------------------------------------------------------
2184// [SECTION] MISC HELPERS/UTILITIES (Color functions)
2185// Note: The Convert functions are early design which are not consistent with other API.
2186//-----------------------------------------------------------------------------
2187
2189{
2190 float t = ((col_b >> IM_COL32_A_SHIFT) & 0xFF) / 255.f;
2191 int r = ImLerp((int)(col_a >> IM_COL32_R_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_R_SHIFT) & 0xFF, t);
2192 int g = ImLerp((int)(col_a >> IM_COL32_G_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_G_SHIFT) & 0xFF, t);
2193 int b = ImLerp((int)(col_a >> IM_COL32_B_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_B_SHIFT) & 0xFF, t);
2194 return IM_COL32(r, g, b, 0xFF);
2195}
2196
2198{
2199 float s = 1.0f / 255.0f;
2200 return ImVec4(
2201 ((in >> IM_COL32_R_SHIFT) & 0xFF) * s,
2202 ((in >> IM_COL32_G_SHIFT) & 0xFF) * s,
2203 ((in >> IM_COL32_B_SHIFT) & 0xFF) * s,
2204 ((in >> IM_COL32_A_SHIFT) & 0xFF) * s);
2205}
2206
2208{
2209 ImU32 out;
2211 out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << IM_COL32_G_SHIFT;
2212 out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << IM_COL32_B_SHIFT;
2213 out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << IM_COL32_A_SHIFT;
2214 return out;
2215}
2216
2217// Convert rgb floats ([0-1],[0-1],[0-1]) to hsv floats ([0-1],[0-1],[0-1]), from Foley & van Dam p592
2218// Optimized http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv
2219void ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v)
2220{
2221 float K = 0.f;
2222 if (g < b)
2223 {
2224 ImSwap(g, b);
2225 K = -1.f;
2226 }
2227 if (r < g)
2228 {
2229 ImSwap(r, g);
2230 K = -2.f / 6.f - K;
2231 }
2232
2233 const float chroma = r - (g < b ? g : b);
2234 out_h = ImFabs(K + (g - b) / (6.f * chroma + 1e-20f));
2235 out_s = chroma / (r + 1e-20f);
2236 out_v = r;
2237}
2238
2239// Convert hsv floats ([0-1],[0-1],[0-1]) to rgb floats ([0-1],[0-1],[0-1]), from Foley & van Dam p593
2240// also http://en.wikipedia.org/wiki/HSL_and_HSV
2241void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b)
2242{
2243 if (s == 0.0f)
2244 {
2245 // gray
2246 out_r = out_g = out_b = v;
2247 return;
2248 }
2249
2250 h = ImFmod(h, 1.0f) / (60.0f / 360.0f);
2251 int i = (int)h;
2252 float f = h - (float)i;
2253 float p = v * (1.0f - s);
2254 float q = v * (1.0f - s * f);
2255 float t = v * (1.0f - s * (1.0f - f));
2256
2257 switch (i)
2258 {
2259 case 0: out_r = v; out_g = t; out_b = p; break;
2260 case 1: out_r = q; out_g = v; out_b = p; break;
2261 case 2: out_r = p; out_g = v; out_b = t; break;
2262 case 3: out_r = p; out_g = q; out_b = v; break;
2263 case 4: out_r = t; out_g = p; out_b = v; break;
2264 case 5: default: out_r = v; out_g = p; out_b = q; break;
2265 }
2266}
2267
2268//-----------------------------------------------------------------------------
2269// [SECTION] ImGuiStorage
2270// Helper: Key->value storage
2271//-----------------------------------------------------------------------------
2272
2273// std::lower_bound but without the bullshit
2275{
2277 ImGuiStorage::ImGuiStoragePair* last = data.Data + data.Size;
2278 size_t count = (size_t)(last - first);
2279 while (count > 0)
2280 {
2281 size_t count2 = count >> 1;
2282 ImGuiStorage::ImGuiStoragePair* mid = first + count2;
2283 if (mid->key < key)
2284 {
2285 first = ++mid;
2286 count -= count2 + 1;
2287 }
2288 else
2289 {
2290 count = count2;
2291 }
2292 }
2293 return first;
2294}
2295
2296// For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once.
2298{
2299 struct StaticFunc
2300 {
2301 static int IMGUI_CDECL PairComparerByID(const void* lhs, const void* rhs)
2302 {
2303 // We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that.
2304 if (((const ImGuiStoragePair*)lhs)->key > ((const ImGuiStoragePair*)rhs)->key) return +1;
2305 if (((const ImGuiStoragePair*)lhs)->key < ((const ImGuiStoragePair*)rhs)->key) return -1;
2306 return 0;
2307 }
2308 };
2309 ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairComparerByID);
2310}
2311
2312int ImGuiStorage::GetInt(ImGuiID key, int default_val) const
2313{
2314 ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
2315 if (it == Data.end() || it->key != key)
2316 return default_val;
2317 return it->val_i;
2318}
2319
2320bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const
2321{
2322 return GetInt(key, default_val ? 1 : 0) != 0;
2323}
2324
2325float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const
2326{
2327 ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
2328 if (it == Data.end() || it->key != key)
2329 return default_val;
2330 return it->val_f;
2331}
2332
2334{
2335 ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
2336 if (it == Data.end() || it->key != key)
2337 return NULL;
2338 return it->val_p;
2339}
2340
2341// References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer.
2342int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val)
2343{
2344 ImGuiStoragePair* it = LowerBound(Data, key);
2345 if (it == Data.end() || it->key != key)
2346 it = Data.insert(it, ImGuiStoragePair(key, default_val));
2347 return &it->val_i;
2348}
2349
2350bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val)
2351{
2352 return (bool*)GetIntRef(key, default_val ? 1 : 0);
2353}
2354
2355float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val)
2356{
2357 ImGuiStoragePair* it = LowerBound(Data, key);
2358 if (it == Data.end() || it->key != key)
2359 it = Data.insert(it, ImGuiStoragePair(key, default_val));
2360 return &it->val_f;
2361}
2362
2363void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)
2364{
2365 ImGuiStoragePair* it = LowerBound(Data, key);
2366 if (it == Data.end() || it->key != key)
2367 it = Data.insert(it, ImGuiStoragePair(key, default_val));
2368 return &it->val_p;
2369}
2370
2371// FIXME-OPT: Need a way to reuse the result of lower_bound when doing GetInt()/SetInt() - not too bad because it only happens on explicit interaction (maximum one a frame)
2373{
2374 ImGuiStoragePair* it = LowerBound(Data, key);
2375 if (it == Data.end() || it->key != key)
2376 {
2377 Data.insert(it, ImGuiStoragePair(key, val));
2378 return;
2379 }
2380 it->val_i = val;
2381}
2382
2384{
2385 SetInt(key, val ? 1 : 0);
2386}
2387
2389{
2390 ImGuiStoragePair* it = LowerBound(Data, key);
2391 if (it == Data.end() || it->key != key)
2392 {
2393 Data.insert(it, ImGuiStoragePair(key, val));
2394 return;
2395 }
2396 it->val_f = val;
2397}
2398
2400{
2401 ImGuiStoragePair* it = LowerBound(Data, key);
2402 if (it == Data.end() || it->key != key)
2403 {
2404 Data.insert(it, ImGuiStoragePair(key, val));
2405 return;
2406 }
2407 it->val_p = val;
2408}
2409
2411{
2412 for (int i = 0; i < Data.Size; i++)
2413 Data[i].val_i = v;
2414}
2415
2416//-----------------------------------------------------------------------------
2417// [SECTION] ImGuiTextFilter
2418//-----------------------------------------------------------------------------
2419
2420// Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]"
2421ImGuiTextFilter::ImGuiTextFilter(const char* default_filter) //-V1077
2422{
2423 InputBuf[0] = 0;
2424 CountGrep = 0;
2425 if (default_filter)
2426 {
2427 ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf));
2428 Build();
2429 }
2430}
2431
2432bool ImGuiTextFilter::Draw(const char* label, float width)
2433{
2434 if (width != 0.0f)
2436 bool value_changed = ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf));
2437 if (value_changed)
2438 Build();
2439 return value_changed;
2440}
2441
2443{
2444 out->resize(0);
2445 const char* wb = b;
2446 const char* we = wb;
2447 while (we < e)
2448 {
2449 if (*we == separator)
2450 {
2451 out->push_back(ImGuiTextRange(wb, we));
2452 wb = we + 1;
2453 }
2454 we++;
2455 }
2456 if (wb != we)
2457 out->push_back(ImGuiTextRange(wb, we));
2458}
2459
2461{
2462 Filters.resize(0);
2463 ImGuiTextRange input_range(InputBuf, InputBuf + strlen(InputBuf));
2464 input_range.split(',', &Filters);
2465
2466 CountGrep = 0;
2467 for (int i = 0; i != Filters.Size; i++)
2468 {
2469 ImGuiTextRange& f = Filters[i];
2470 while (f.b < f.e && ImCharIsBlankA(f.b[0]))
2471 f.b++;
2472 while (f.e > f.b && ImCharIsBlankA(f.e[-1]))
2473 f.e--;
2474 if (f.empty())
2475 continue;
2476 if (Filters[i].b[0] != '-')
2477 CountGrep += 1;
2478 }
2479}
2480
2481bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const
2482{
2483 if (Filters.empty())
2484 return true;
2485
2486 if (text == NULL)
2487 text = "";
2488
2489 for (int i = 0; i != Filters.Size; i++)
2490 {
2491 const ImGuiTextRange& f = Filters[i];
2492 if (f.empty())
2493 continue;
2494 if (f.b[0] == '-')
2495 {
2496 // Subtract
2497 if (ImStristr(text, text_end, f.b + 1, f.e) != NULL)
2498 return false;
2499 }
2500 else
2501 {
2502 // Grep
2503 if (ImStristr(text, text_end, f.b, f.e) != NULL)
2504 return true;
2505 }
2506 }
2507
2508 // Implicit * grep
2509 if (CountGrep == 0)
2510 return true;
2511
2512 return false;
2513}
2514
2515//-----------------------------------------------------------------------------
2516// [SECTION] ImGuiTextBuffer, ImGuiTextIndex
2517//-----------------------------------------------------------------------------
2518
2519// On some platform vsnprintf() takes va_list by reference and modifies it.
2520// va_copy is the 'correct' way to copy a va_list but Visual Studio prior to 2013 doesn't have it.
2521#ifndef va_copy
2522#if defined(__GNUC__) || defined(__clang__)
2523#define va_copy(dest, src) __builtin_va_copy(dest, src)
2524#else
2525#define va_copy(dest, src) (dest = src)
2526#endif
2527#endif
2528
2529char ImGuiTextBuffer::EmptyString[1] = { 0 };
2530
2531void ImGuiTextBuffer::append(const char* str, const char* str_end)
2532{
2533 int len = str_end ? (int)(str_end - str) : (int)strlen(str);
2534
2535 // Add zero-terminator the first time
2536 const int write_off = (Buf.Size != 0) ? Buf.Size : 1;
2537 const int needed_sz = write_off + len;
2538 if (write_off + len >= Buf.Capacity)
2539 {
2540 int new_capacity = Buf.Capacity * 2;
2541 Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity);
2542 }
2543
2544 Buf.resize(needed_sz);
2545 memcpy(&Buf[write_off - 1], str, (size_t)len);
2546 Buf[write_off - 1 + len] = 0;
2547}
2548
2549void ImGuiTextBuffer::appendf(const char* fmt, ...)
2550{
2551 va_list args;
2552 va_start(args, fmt);
2553 appendfv(fmt, args);
2554 va_end(args);
2555}
2556
2557// Helper: Text buffer for logging/accumulating text
2558void ImGuiTextBuffer::appendfv(const char* fmt, va_list args)
2559{
2560 va_list args_copy;
2561 va_copy(args_copy, args);
2562
2563 int len = ImFormatStringV(NULL, 0, fmt, args); // FIXME-OPT: could do a first pass write attempt, likely successful on first pass.
2564 if (len <= 0)
2565 {
2566 va_end(args_copy);
2567 return;
2568 }
2569
2570 // Add zero-terminator the first time
2571 const int write_off = (Buf.Size != 0) ? Buf.Size : 1;
2572 const int needed_sz = write_off + len;
2573 if (write_off + len >= Buf.Capacity)
2574 {
2575 int new_capacity = Buf.Capacity * 2;
2576 Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity);
2577 }
2578
2579 Buf.resize(needed_sz);
2580 ImFormatStringV(&Buf[write_off - 1], (size_t)len + 1, fmt, args_copy);
2581 va_end(args_copy);
2582}
2583
2584void ImGuiTextIndex::append(const char* base, int old_size, int new_size)
2585{
2586 IM_ASSERT(old_size >= 0 && new_size >= old_size && new_size >= EndOffset);
2587 if (old_size == new_size)
2588 return;
2589 if (EndOffset == 0 || base[EndOffset - 1] == '\n')
2590 LineOffsets.push_back(EndOffset);
2591 const char* base_end = base + new_size;
2592 for (const char* p = base + old_size; (p = (const char*)memchr(p, '\n', base_end - p)) != 0; )
2593 if (++p < base_end) // Don't push a trailing offset on last \n
2594 LineOffsets.push_back((int)(intptr_t)(p - base));
2595 EndOffset = ImMax(EndOffset, new_size);
2596}
2597
2598//-----------------------------------------------------------------------------
2599// [SECTION] ImGuiListClipper
2600// This is currently not as flexible/powerful as it should be and really confusing/spaghetti, mostly because we changed
2601// the API mid-way through development and support two ways to using the clipper, needs some rework (see TODO)
2602//-----------------------------------------------------------------------------
2603
2604// FIXME-TABLE: This prevents us from using ImGuiListClipper _inside_ a table cell.
2605// The problem we have is that without a Begin/End scheme for rows using the clipper is ambiguous.
2606static bool GetSkipItemForListClipping()
2607{
2608 ImGuiContext& g = *GImGui;
2609 return (g.CurrentTable ? g.CurrentTable->HostSkipItems : g.CurrentWindow->SkipItems);
2610}
2611
2612#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
2613// Legacy helper to calculate coarse clipping of large list of evenly sized items.
2614// This legacy API is not ideal because it assumes we will return a single contiguous rectangle.
2615// Prefer using ImGuiListClipper which can returns non-contiguous ranges.
2616void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end)
2617{
2618 ImGuiContext& g = *GImGui;
2619 ImGuiWindow* window = g.CurrentWindow;
2620 if (g.LogEnabled)
2621 {
2622 // If logging is active, do not perform any clipping
2623 *out_items_display_start = 0;
2624 *out_items_display_end = items_count;
2625 return;
2626 }
2627 if (GetSkipItemForListClipping())
2628 {
2629 *out_items_display_start = *out_items_display_end = 0;
2630 return;
2631 }
2632
2633 // We create the union of the ClipRect and the scoring rect which at worst should be 1 page away from ClipRect
2634 // We don't include g.NavId's rectangle in there (unless g.NavJustMovedToId is set) because the rectangle enlargement can get costly.
2635 ImRect rect = window->ClipRect;
2636 if (g.NavMoveScoringItems)
2637 rect.Add(g.NavScoringNoClipRect);
2638 if (g.NavJustMovedToId && window->NavLastIds[0] == g.NavJustMovedToId)
2639 rect.Add(WindowRectRelToAbs(window, window->NavRectRel[0])); // Could store and use NavJustMovedToRectRel
2640
2641 const ImVec2 pos = window->DC.CursorPos;
2642 int start = (int)((rect.Min.y - pos.y) / items_height);
2643 int end = (int)((rect.Max.y - pos.y) / items_height);
2644
2645 // When performing a navigation request, ensure we have one item extra in the direction we are moving to
2646 // FIXME: Verify this works with tabbing
2647 const bool is_nav_request = (g.NavMoveScoringItems && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav);
2648 if (is_nav_request && g.NavMoveClipDir == ImGuiDir_Up)
2649 start--;
2650 if (is_nav_request && g.NavMoveClipDir == ImGuiDir_Down)
2651 end++;
2652
2653 start = ImClamp(start, 0, items_count);
2654 end = ImClamp(end + 1, start, items_count);
2655 *out_items_display_start = start;
2656 *out_items_display_end = end;
2657}
2658#endif
2659
2660static void ImGuiListClipper_SortAndFuseRanges(ImVector<ImGuiListClipperRange>& ranges, int offset = 0)
2661{
2662 if (ranges.Size - offset <= 1)
2663 return;
2664
2665 // Helper to order ranges and fuse them together if possible (bubble sort is fine as we are only sorting 2-3 entries)
2666 for (int sort_end = ranges.Size - offset - 1; sort_end > 0; --sort_end)
2667 for (int i = offset; i < sort_end + offset; ++i)
2668 if (ranges[i].Min > ranges[i + 1].Min)
2669 ImSwap(ranges[i], ranges[i + 1]);
2670
2671 // Now fuse ranges together as much as possible.
2672 for (int i = 1 + offset; i < ranges.Size; i++)
2673 {
2674 IM_ASSERT(!ranges[i].PosToIndexConvert && !ranges[i - 1].PosToIndexConvert);
2675 if (ranges[i - 1].Max < ranges[i].Min)
2676 continue;
2677 ranges[i - 1].Min = ImMin(ranges[i - 1].Min, ranges[i].Min);
2678 ranges[i - 1].Max = ImMax(ranges[i - 1].Max, ranges[i].Max);
2679 ranges.erase(ranges.Data + i);
2680 i--;
2681 }
2682}
2683
2684static void ImGuiListClipper_SeekCursorAndSetupPrevLine(float pos_y, float line_height)
2685{
2686 // Set cursor position and a few other things so that SetScrollHereY() and Columns() can work when seeking cursor.
2687 // FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue.
2688 // The clipper should probably have a final step to display the last item in a regular manner, maybe with an opt-out flag for data sets which may have costly seek?
2689 ImGuiContext& g = *GImGui;
2690 ImGuiWindow* window = g.CurrentWindow;
2691 float off_y = pos_y - window->DC.CursorPos.y;
2692 window->DC.CursorPos.y = pos_y;
2693 window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, pos_y - g.Style.ItemSpacing.y);
2694 window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; // Setting those fields so that SetScrollHereY() can properly function after the end of our clipper usage.
2695 window->DC.PrevLineSize.y = (line_height - g.Style.ItemSpacing.y); // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list.
2696 if (ImGuiOldColumns* columns = window->DC.CurrentColumns)
2697 columns->LineMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly
2698 if (ImGuiTable* table = g.CurrentTable)
2699 {
2700 if (table->IsInsideRow)
2701 ImGui::TableEndRow(table);
2702 table->RowPosY2 = window->DC.CursorPos.y;
2703 const int row_increase = (int)((off_y / line_height) + 0.5f);
2704 //table->CurrentRow += row_increase; // Can't do without fixing TableEndRow()
2705 table->RowBgColorCounter += row_increase;
2706 }
2707}
2708
2709static void ImGuiListClipper_SeekCursorForItem(ImGuiListClipper* clipper, int item_n)
2710{
2711 // StartPosY starts from ItemsFrozen hence the subtraction
2712 // Perform the add and multiply with double to allow seeking through larger ranges
2714 float pos_y = (float)((double)clipper->StartPosY + data->LossynessOffset + (double)(item_n - data->ItemsFrozen) * clipper->ItemsHeight);
2715 ImGuiListClipper_SeekCursorAndSetupPrevLine(pos_y, clipper->ItemsHeight);
2716}
2717
2719{
2720 memset(this, 0, sizeof(*this));
2722 IM_ASSERT(Ctx != NULL);
2723 ItemsCount = -1;
2724}
2725
2727{
2728 End();
2729}
2730
2731void ImGuiListClipper::Begin(int items_count, float items_height)
2732{
2733 ImGuiContext& g = *Ctx;
2734 ImGuiWindow* window = g.CurrentWindow;
2735 IMGUI_DEBUG_LOG_CLIPPER("Clipper: Begin(%d,%.2f) in '%s'\n", items_count, items_height, window->Name);
2736
2737 if (ImGuiTable* table = g.CurrentTable)
2738 if (table->IsInsideRow)
2739 ImGui::TableEndRow(table);
2740
2741 StartPosY = window->DC.CursorPos.y;
2742 ItemsHeight = items_height;
2743 ItemsCount = items_count;
2744 DisplayStart = -1;
2745 DisplayEnd = 0;
2746
2747 // Acquire temporary buffer
2751 data->Reset(this);
2753 TempData = data;
2754}
2755
2757{
2758 ImGuiContext& g = *Ctx;
2759 if (ImGuiListClipperData* data = (ImGuiListClipperData*)TempData)
2760 {
2761 // In theory here we should assert that we are already at the right position, but it seems saner to just seek at the end and not assert/crash the user.
2762 IMGUI_DEBUG_LOG_CLIPPER("Clipper: End() in '%s'\n", g.CurrentWindow->Name);
2763 if (ItemsCount >= 0 && ItemsCount < INT_MAX && DisplayStart >= 0)
2764 ImGuiListClipper_SeekCursorForItem(this, ItemsCount);
2765
2766 // Restore temporary buffer and fix back pointers which may be invalidated when nesting
2767 IM_ASSERT(data->ListClipper == this);
2768 data->StepNo = data->Ranges.Size;
2769 if (--g.ClipperTempDataStacked > 0)
2770 {
2771 data = &g.ClipperTempData[g.ClipperTempDataStacked - 1];
2772 data->ListClipper->TempData = data;
2773 }
2774 TempData = NULL;
2775 }
2776 ItemsCount = -1;
2777}
2778
2779void ImGuiListClipper::ForceDisplayRangeByIndices(int item_min, int item_max)
2780{
2781 ImGuiListClipperData* data = (ImGuiListClipperData*)TempData;
2782 IM_ASSERT(DisplayStart < 0); // Only allowed after Begin() and if there has not been a specified range yet.
2783 IM_ASSERT(item_min <= item_max);
2784 if (item_min < item_max)
2785 data->Ranges.push_back(ImGuiListClipperRange::FromIndices(item_min, item_max));
2786}
2787
2788static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper)
2789{
2790 ImGuiContext& g = *clipper->Ctx;
2791 ImGuiWindow* window = g.CurrentWindow;
2793 IM_ASSERT(data != NULL && "Called ImGuiListClipper::Step() too many times, or before ImGuiListClipper::Begin() ?");
2794
2795 ImGuiTable* table = g.CurrentTable;
2796 if (table && table->IsInsideRow)
2797 ImGui::TableEndRow(table);
2798
2799 // No items
2800 if (clipper->ItemsCount == 0 || GetSkipItemForListClipping())
2801 return false;
2802
2803 // While we are in frozen row state, keep displaying items one by one, unclipped
2804 // FIXME: Could be stored as a table-agnostic state.
2805 if (data->StepNo == 0 && table != NULL && !table->IsUnfrozenRows)
2806 {
2807 clipper->DisplayStart = data->ItemsFrozen;
2808 clipper->DisplayEnd = ImMin(data->ItemsFrozen + 1, clipper->ItemsCount);
2809 if (clipper->DisplayStart < clipper->DisplayEnd)
2810 data->ItemsFrozen++;
2811 return true;
2812 }
2813
2814 // Step 0: Let you process the first element (regardless of it being visible or not, so we can measure the element height)
2815 bool calc_clipping = false;
2816 if (data->StepNo == 0)
2817 {
2818 clipper->StartPosY = window->DC.CursorPos.y;
2819 if (clipper->ItemsHeight <= 0.0f)
2820 {
2821 // Submit the first item (or range) so we can measure its height (generally the first range is 0..1)
2822 data->Ranges.push_front(ImGuiListClipperRange::FromIndices(data->ItemsFrozen, data->ItemsFrozen + 1));
2823 clipper->DisplayStart = ImMax(data->Ranges[0].Min, data->ItemsFrozen);
2824 clipper->DisplayEnd = ImMin(data->Ranges[0].Max, clipper->ItemsCount);
2825 data->StepNo = 1;
2826 return true;
2827 }
2828 calc_clipping = true; // If on the first step with known item height, calculate clipping.
2829 }
2830
2831 // Step 1: Let the clipper infer height from first range
2832 if (clipper->ItemsHeight <= 0.0f)
2833 {
2834 IM_ASSERT(data->StepNo == 1);
2835 if (table)
2836 IM_ASSERT(table->RowPosY1 == clipper->StartPosY && table->RowPosY2 == window->DC.CursorPos.y);
2837
2838 clipper->ItemsHeight = (window->DC.CursorPos.y - clipper->StartPosY) / (float)(clipper->DisplayEnd - clipper->DisplayStart);
2839 bool affected_by_floating_point_precision = ImIsFloatAboveGuaranteedIntegerPrecision(clipper->StartPosY) || ImIsFloatAboveGuaranteedIntegerPrecision(window->DC.CursorPos.y);
2840 if (affected_by_floating_point_precision)
2841 clipper->ItemsHeight = window->DC.PrevLineSize.y + g.Style.ItemSpacing.y; // FIXME: Technically wouldn't allow multi-line entries.
2842
2843 IM_ASSERT(clipper->ItemsHeight > 0.0f && "Unable to calculate item height! First item hasn't moved the cursor vertically!");
2844 calc_clipping = true; // If item height had to be calculated, calculate clipping afterwards.
2845 }
2846
2847 // Step 0 or 1: Calculate the actual ranges of visible elements.
2848 const int already_submitted = clipper->DisplayEnd;
2849 if (calc_clipping)
2850 {
2851 if (g.LogEnabled)
2852 {
2853 // If logging is active, do not perform any clipping
2854 data->Ranges.push_back(ImGuiListClipperRange::FromIndices(0, clipper->ItemsCount));
2855 }
2856 else
2857 {
2858 // Add range selected to be included for navigation
2859 const bool is_nav_request = (g.NavMoveScoringItems && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav);
2860 if (is_nav_request)
2862 if (is_nav_request && (g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) && g.NavTabbingDir == -1)
2863 data->Ranges.push_back(ImGuiListClipperRange::FromIndices(clipper->ItemsCount - 1, clipper->ItemsCount));
2864
2865 // Add focused/active item
2866 ImRect nav_rect_abs = ImGui::WindowRectRelToAbs(window, window->NavRectRel[0]);
2867 if (g.NavId != 0 && window->NavLastIds[0] == g.NavId)
2868 data->Ranges.push_back(ImGuiListClipperRange::FromPositions(nav_rect_abs.Min.y, nav_rect_abs.Max.y, 0, 0));
2869
2870 // Add visible range
2871 const int off_min = (is_nav_request && g.NavMoveClipDir == ImGuiDir_Up) ? -1 : 0;
2872 const int off_max = (is_nav_request && g.NavMoveClipDir == ImGuiDir_Down) ? 1 : 0;
2873 data->Ranges.push_back(ImGuiListClipperRange::FromPositions(window->ClipRect.Min.y, window->ClipRect.Max.y, off_min, off_max));
2874 }
2875
2876 // Convert position ranges to item index ranges
2877 // - Very important: when a starting position is after our maximum item, we set Min to (ItemsCount - 1). This allows us to handle most forms of wrapping.
2878 // - Due to how Selectable extra padding they tend to be "unaligned" with exact unit in the item list,
2879 // which with the flooring/ceiling tend to lead to 2 items instead of one being submitted.
2880 for (int i = 0; i < data->Ranges.Size; i++)
2881 if (data->Ranges[i].PosToIndexConvert)
2882 {
2883 int m1 = (int)(((double)data->Ranges[i].Min - window->DC.CursorPos.y - data->LossynessOffset) / clipper->ItemsHeight);
2884 int m2 = (int)((((double)data->Ranges[i].Max - window->DC.CursorPos.y - data->LossynessOffset) / clipper->ItemsHeight) + 0.999999f);
2885 data->Ranges[i].Min = ImClamp(already_submitted + m1 + data->Ranges[i].PosToIndexOffsetMin, already_submitted, clipper->ItemsCount - 1);
2886 data->Ranges[i].Max = ImClamp(already_submitted + m2 + data->Ranges[i].PosToIndexOffsetMax, data->Ranges[i].Min + 1, clipper->ItemsCount);
2887 data->Ranges[i].PosToIndexConvert = false;
2888 }
2889 ImGuiListClipper_SortAndFuseRanges(data->Ranges, data->StepNo);
2890 }
2891
2892 // Step 0+ (if item height is given in advance) or 1+: Display the next range in line.
2893 if (data->StepNo < data->Ranges.Size)
2894 {
2895 clipper->DisplayStart = ImMax(data->Ranges[data->StepNo].Min, already_submitted);
2896 clipper->DisplayEnd = ImMin(data->Ranges[data->StepNo].Max, clipper->ItemsCount);
2897 if (clipper->DisplayStart > already_submitted) //-V1051
2898 ImGuiListClipper_SeekCursorForItem(clipper, clipper->DisplayStart);
2899 data->StepNo++;
2900 return true;
2901 }
2902
2903 // After the last step: Let the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd),
2904 // Advance the cursor to the end of the list and then returns 'false' to end the loop.
2905 if (clipper->ItemsCount < INT_MAX)
2906 ImGuiListClipper_SeekCursorForItem(clipper, clipper->ItemsCount);
2907
2908 return false;
2909}
2910
2912{
2913 ImGuiContext& g = *Ctx;
2914 bool need_items_height = (ItemsHeight <= 0.0f);
2915 bool ret = ImGuiListClipper_StepInternal(this);
2916 if (ret && (DisplayStart == DisplayEnd))
2917 ret = false;
2918 if (g.CurrentTable && g.CurrentTable->IsUnfrozenRows == false)
2919 IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): inside frozen table row.\n");
2920 if (need_items_height && ItemsHeight > 0.0f)
2921 IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): computed ItemsHeight: %.2f.\n", ItemsHeight);
2922 if (ret)
2923 {
2924 IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): display %d to %d.\n", DisplayStart, DisplayEnd);
2925 }
2926 else
2927 {
2928 IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): End.\n");
2929 End();
2930 }
2931 return ret;
2932}
2933
2934//-----------------------------------------------------------------------------
2935// [SECTION] STYLING
2936//-----------------------------------------------------------------------------
2937
2939{
2940 IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
2941 return GImGui->Style;
2942}
2943
2944ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul)
2945{
2946 ImGuiStyle& style = GImGui->Style;
2947 ImVec4 c = style.Colors[idx];
2948 c.w *= style.Alpha * alpha_mul;
2949 return ColorConvertFloat4ToU32(c);
2950}
2951
2953{
2954 ImGuiStyle& style = GImGui->Style;
2955 ImVec4 c = col;
2956 c.w *= style.Alpha;
2957 return ColorConvertFloat4ToU32(c);
2958}
2959
2961{
2962 ImGuiStyle& style = GImGui->Style;
2963 return style.Colors[idx];
2964}
2965
2967{
2968 ImGuiStyle& style = GImGui->Style;
2969 if (style.Alpha >= 1.0f)
2970 return col;
2971 ImU32 a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT;
2972 a = (ImU32)(a * style.Alpha); // We don't need to clamp 0..255 because Style.Alpha is in 0..1 range.
2973 return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT);
2974}
2975
2976// FIXME: This may incur a round-trip (if the end user got their data from a float4) but eventually we aim to store the in-flight colors as ImU32
2978{
2979 ImGuiContext& g = *GImGui;
2980 ImGuiColorMod backup;
2981 backup.Col = idx;
2982 backup.BackupValue = g.Style.Colors[idx];
2983 g.ColorStack.push_back(backup);
2984 g.Style.Colors[idx] = ColorConvertU32ToFloat4(col);
2985}
2986
2988{
2989 ImGuiContext& g = *GImGui;
2990 ImGuiColorMod backup;
2991 backup.Col = idx;
2992 backup.BackupValue = g.Style.Colors[idx];
2993 g.ColorStack.push_back(backup);
2994 g.Style.Colors[idx] = col;
2995}
2996
2998{
2999 ImGuiContext& g = *GImGui;
3000 if (g.ColorStack.Size < count)
3001 {
3002 IM_ASSERT_USER_ERROR(g.ColorStack.Size > count, "Calling PopStyleColor() too many times: stack underflow.");
3003 count = g.ColorStack.Size;
3004 }
3005 while (count > 0)
3006 {
3007 ImGuiColorMod& backup = g.ColorStack.back();
3008 g.Style.Colors[backup.Col] = backup.BackupValue;
3009 g.ColorStack.pop_back();
3010 count--;
3011 }
3012}
3013
3014static const ImGuiDataVarInfo GStyleVarInfo[] =
3015{
3016 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) }, // ImGuiStyleVar_Alpha
3017 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, DisabledAlpha) }, // ImGuiStyleVar_DisabledAlpha
3018 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) }, // ImGuiStyleVar_WindowPadding
3019 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) }, // ImGuiStyleVar_WindowRounding
3020 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowBorderSize) }, // ImGuiStyleVar_WindowBorderSize
3021 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowMinSize) }, // ImGuiStyleVar_WindowMinSize
3022 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowTitleAlign) }, // ImGuiStyleVar_WindowTitleAlign
3023 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildRounding) }, // ImGuiStyleVar_ChildRounding
3024 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildBorderSize) }, // ImGuiStyleVar_ChildBorderSize
3025 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupRounding) }, // ImGuiStyleVar_PopupRounding
3026 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupBorderSize) }, // ImGuiStyleVar_PopupBorderSize
3027 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, FramePadding) }, // ImGuiStyleVar_FramePadding
3028 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameRounding) }, // ImGuiStyleVar_FrameRounding
3029 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameBorderSize) }, // ImGuiStyleVar_FrameBorderSize
3030 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemSpacing) }, // ImGuiStyleVar_ItemSpacing
3031 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) }, // ImGuiStyleVar_ItemInnerSpacing
3032 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) }, // ImGuiStyleVar_IndentSpacing
3033 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, CellPadding) }, // ImGuiStyleVar_CellPadding
3034 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarSize) }, // ImGuiStyleVar_ScrollbarSize
3035 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarRounding) }, // ImGuiStyleVar_ScrollbarRounding
3036 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize
3037 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding
3038 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding
3039 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign
3040 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign
3041 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, SeparatorTextBorderSize) },// ImGuiStyleVar_SeparatorTextBorderSize
3042 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SeparatorTextAlign) }, // ImGuiStyleVar_SeparatorTextAlign
3043 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SeparatorTextPadding) }, // ImGuiStyleVar_SeparatorTextPadding
3044};
3045
3047{
3048 IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT);
3050 return &GStyleVarInfo[idx];
3051}
3052
3054{
3055 ImGuiContext& g = *GImGui;
3056 const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx);
3057 if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1)
3058 {
3059 float* pvar = (float*)var_info->GetVarPtr(&g.Style);
3060 g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar));
3061 *pvar = val;
3062 return;
3063 }
3064 IM_ASSERT_USER_ERROR(0, "Called PushStyleVar() variant with wrong type!");
3065}
3066
3068{
3069 ImGuiContext& g = *GImGui;
3070 const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx);
3071 if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2)
3072 {
3073 ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style);
3074 g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar));
3075 *pvar = val;
3076 return;
3077 }
3078 IM_ASSERT_USER_ERROR(0, "Called PushStyleVar() variant with wrong type!");
3079}
3080
3081void ImGui::PopStyleVar(int count)
3082{
3083 ImGuiContext& g = *GImGui;
3084 if (g.StyleVarStack.Size < count)
3085 {
3086 IM_ASSERT_USER_ERROR(g.StyleVarStack.Size > count, "Calling PopStyleVar() too many times: stack underflow.");
3087 count = g.StyleVarStack.Size;
3088 }
3089 while (count > 0)
3090 {
3091 // We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it.
3092 ImGuiStyleMod& backup = g.StyleVarStack.back();
3093 const ImGuiDataVarInfo* info = GetStyleVarInfo(backup.VarIdx);
3094 void* data = info->GetVarPtr(&g.Style);
3095 if (info->Type == ImGuiDataType_Float && info->Count == 1) { ((float*)data)[0] = backup.BackupFloat[0]; }
3096 else if (info->Type == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; }
3098 count--;
3099 }
3100}
3101
3103{
3104 // Create switch-case from enum with regexp: ImGuiCol_{.*}, --> case ImGuiCol_\1: return "\1";
3105 switch (idx)
3106 {
3107 case ImGuiCol_Text: return "Text";
3108 case ImGuiCol_TextDisabled: return "TextDisabled";
3109 case ImGuiCol_WindowBg: return "WindowBg";
3110 case ImGuiCol_ChildBg: return "ChildBg";
3111 case ImGuiCol_PopupBg: return "PopupBg";
3112 case ImGuiCol_Border: return "Border";
3113 case ImGuiCol_BorderShadow: return "BorderShadow";
3114 case ImGuiCol_FrameBg: return "FrameBg";
3115 case ImGuiCol_FrameBgHovered: return "FrameBgHovered";
3116 case ImGuiCol_FrameBgActive: return "FrameBgActive";
3117 case ImGuiCol_TitleBg: return "TitleBg";
3118 case ImGuiCol_TitleBgActive: return "TitleBgActive";
3119 case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed";
3120 case ImGuiCol_MenuBarBg: return "MenuBarBg";
3121 case ImGuiCol_ScrollbarBg: return "ScrollbarBg";
3122 case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab";
3123 case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered";
3124 case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive";
3125 case ImGuiCol_CheckMark: return "CheckMark";
3126 case ImGuiCol_SliderGrab: return "SliderGrab";
3127 case ImGuiCol_SliderGrabActive: return "SliderGrabActive";
3128 case ImGuiCol_Button: return "Button";
3129 case ImGuiCol_ButtonHovered: return "ButtonHovered";
3130 case ImGuiCol_ButtonActive: return "ButtonActive";
3131 case ImGuiCol_Header: return "Header";
3132 case ImGuiCol_HeaderHovered: return "HeaderHovered";
3133 case ImGuiCol_HeaderActive: return "HeaderActive";
3134 case ImGuiCol_Separator: return "Separator";
3135 case ImGuiCol_SeparatorHovered: return "SeparatorHovered";
3136 case ImGuiCol_SeparatorActive: return "SeparatorActive";
3137 case ImGuiCol_ResizeGrip: return "ResizeGrip";
3138 case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered";
3139 case ImGuiCol_ResizeGripActive: return "ResizeGripActive";
3140 case ImGuiCol_Tab: return "Tab";
3141 case ImGuiCol_TabHovered: return "TabHovered";
3142 case ImGuiCol_TabActive: return "TabActive";
3143 case ImGuiCol_TabUnfocused: return "TabUnfocused";
3144 case ImGuiCol_TabUnfocusedActive: return "TabUnfocusedActive";
3145 case ImGuiCol_PlotLines: return "PlotLines";
3146 case ImGuiCol_PlotLinesHovered: return "PlotLinesHovered";
3147 case ImGuiCol_PlotHistogram: return "PlotHistogram";
3148 case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered";
3149 case ImGuiCol_TableHeaderBg: return "TableHeaderBg";
3150 case ImGuiCol_TableBorderStrong: return "TableBorderStrong";
3151 case ImGuiCol_TableBorderLight: return "TableBorderLight";
3152 case ImGuiCol_TableRowBg: return "TableRowBg";
3153 case ImGuiCol_TableRowBgAlt: return "TableRowBgAlt";
3154 case ImGuiCol_TextSelectedBg: return "TextSelectedBg";
3155 case ImGuiCol_DragDropTarget: return "DragDropTarget";
3156 case ImGuiCol_NavHighlight: return "NavHighlight";
3157 case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight";
3158 case ImGuiCol_NavWindowingDimBg: return "NavWindowingDimBg";
3159 case ImGuiCol_ModalWindowDimBg: return "ModalWindowDimBg";
3160 }
3161 IM_ASSERT(0);
3162 return "Unknown";
3163}
3164
3165
3166//-----------------------------------------------------------------------------
3167// [SECTION] RENDER HELPERS
3168// Some of those (internal) functions are currently quite a legacy mess - their signature and behavior will change,
3169// we need a nicer separation between low-level functions and high-level functions relying on the ImGui context.
3170// Also see imgui_draw.cpp for some more which have been reworked to not rely on ImGui:: context.
3171//-----------------------------------------------------------------------------
3172
3173const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end)
3174{
3175 const char* text_display_end = text;
3176 if (!text_end)
3177 text_end = (const char*)-1;
3178
3179 while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#'))
3180 text_display_end++;
3181 return text_display_end;
3182}
3183
3184// Internal ImGui functions to render text
3185// RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText()
3186void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash)
3187{
3188 ImGuiContext& g = *GImGui;
3189 ImGuiWindow* window = g.CurrentWindow;
3190
3191 // Hide anything after a '##' string
3192 const char* text_display_end;
3193 if (hide_text_after_hash)
3194 {
3195 text_display_end = FindRenderedTextEnd(text, text_end);
3196 }
3197 else
3198 {
3199 if (!text_end)
3200 text_end = text + strlen(text); // FIXME-OPT
3201 text_display_end = text_end;
3202 }
3203
3204 if (text != text_display_end)
3205 {
3206 window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end);
3207 if (g.LogEnabled)
3208 LogRenderedText(&pos, text, text_display_end);
3209 }
3210}
3211
3212void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width)
3213{
3214 ImGuiContext& g = *GImGui;
3215 ImGuiWindow* window = g.CurrentWindow;
3216
3217 if (!text_end)
3218 text_end = text + strlen(text); // FIXME-OPT
3219
3220 if (text != text_end)
3221 {
3222 window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width);
3223 if (g.LogEnabled)
3224 LogRenderedText(&pos, text, text_end);
3225 }
3226}
3227
3228// Default clip_rect uses (pos_min,pos_max)
3229// Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges)
3230void ImGui::RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_display_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect)
3231{
3232 // Perform CPU side clipping for single clipped element to avoid using scissor state
3233 ImVec2 pos = pos_min;
3234 const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f);
3235
3236 const ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min;
3237 const ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max;
3238 bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y);
3239 if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min
3240 need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y);
3241
3242 // Align whole block. We should defer that to the better rendering function when we'll have support for individual line alignment.
3243 if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x);
3244 if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y);
3245
3246 // Render
3247 if (need_clipping)
3248 {
3249 ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y);
3250 draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect);
3251 }
3252 else
3253 {
3254 draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL);
3255 }
3256}
3257
3258void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect)
3259{
3260 // Hide anything after a '##' string
3261 const char* text_display_end = FindRenderedTextEnd(text, text_end);
3262 const int text_len = (int)(text_display_end - text);
3263 if (text_len == 0)
3264 return;
3265
3266 ImGuiContext& g = *GImGui;
3267 ImGuiWindow* window = g.CurrentWindow;
3268 RenderTextClippedEx(window->DrawList, pos_min, pos_max, text, text_display_end, text_size_if_known, align, clip_rect);
3269 if (g.LogEnabled)
3270 LogRenderedText(&pos_min, text, text_display_end);
3271}
3272
3273// Another overly complex function until we reorganize everything into a nice all-in-one helper.
3274// This is made more complex because we have dissociated the layout rectangle (pos_min..pos_max) which define _where_ the ellipsis is, from actual clipping of text and limit of the ellipsis display.
3275// This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move.
3276void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end_full, const ImVec2* text_size_if_known)
3277{
3278 ImGuiContext& g = *GImGui;
3279 if (text_end_full == NULL)
3280 text_end_full = FindRenderedTextEnd(text);
3281 const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_end_full, false, 0.0f);
3282
3283 //draw_list->AddLine(ImVec2(pos_max.x, pos_min.y - 4), ImVec2(pos_max.x, pos_max.y + 4), IM_COL32(0, 0, 255, 255));
3284 //draw_list->AddLine(ImVec2(ellipsis_max_x, pos_min.y-2), ImVec2(ellipsis_max_x, pos_max.y+2), IM_COL32(0, 255, 0, 255));
3285 //draw_list->AddLine(ImVec2(clip_max_x, pos_min.y), ImVec2(clip_max_x, pos_max.y), IM_COL32(255, 0, 0, 255));
3286 // FIXME: We could technically remove (last_glyph->AdvanceX - last_glyph->X1) from text_size.x here and save a few pixels.
3287 if (text_size.x > pos_max.x - pos_min.x)
3288 {
3289 // Hello wo...
3290 // | | |
3291 // min max ellipsis_max
3292 // <-> this is generally some padding value
3293
3294 const ImFont* font = draw_list->_Data->Font;
3295 const float font_size = draw_list->_Data->FontSize;
3296 const float font_scale = font_size / font->FontSize;
3297 const char* text_end_ellipsis = NULL;
3298 const float ellipsis_width = font->EllipsisWidth * font_scale;
3299
3300 // We can now claim the space between pos_max.x and ellipsis_max.x
3301 const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_width) - pos_min.x, 1.0f);
3302 float text_size_clipped_x = font->CalcTextSizeA(font_size, text_avail_width, 0.0f, text, text_end_full, &text_end_ellipsis).x;
3303 if (text == text_end_ellipsis && text_end_ellipsis < text_end_full)
3304 {
3305 // Always display at least 1 character if there's no room for character + ellipsis
3306 text_end_ellipsis = text + ImTextCountUtf8BytesFromChar(text, text_end_full);
3307 text_size_clipped_x = font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text, text_end_ellipsis).x;
3308 }
3309 while (text_end_ellipsis > text && ImCharIsBlankA(text_end_ellipsis[-1]))
3310 {
3311 // Trim trailing space before ellipsis (FIXME: Supporting non-ascii blanks would be nice, for this we need a function to backtrack in UTF-8 text)
3312 text_end_ellipsis--;
3313 text_size_clipped_x -= font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text_end_ellipsis, text_end_ellipsis + 1).x; // Ascii blanks are always 1 byte
3314 }
3315
3316 // Render text, render ellipsis
3317 RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f));
3318 ImVec2 ellipsis_pos = ImFloor(ImVec2(pos_min.x + text_size_clipped_x, pos_min.y));
3319 if (ellipsis_pos.x + ellipsis_width <= ellipsis_max_x)
3320 for (int i = 0; i < font->EllipsisCharCount; i++, ellipsis_pos.x += font->EllipsisCharStep * font_scale)
3321 font->RenderChar(draw_list, font_size, ellipsis_pos, GetColorU32(ImGuiCol_Text), font->EllipsisChar);
3322 }
3323 else
3324 {
3325 RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_full, &text_size, ImVec2(0.0f, 0.0f));
3326 }
3327
3328 if (g.LogEnabled)
3329 LogRenderedText(&pos_min, text, text_end_full);
3330}
3331
3332// Render a rectangle shaped with optional rounding and borders
3333void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding)
3334{
3335 ImGuiContext& g = *GImGui;
3336 ImGuiWindow* window = g.CurrentWindow;
3337 window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding);
3338 const float border_size = g.Style.FrameBorderSize;
3339 if (border && border_size > 0.0f)
3340 {
3341 window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, 0, border_size);
3342 window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, 0, border_size);
3343 }
3344}
3345
3346void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding)
3347{
3348 ImGuiContext& g = *GImGui;
3349 ImGuiWindow* window = g.CurrentWindow;
3350 const float border_size = g.Style.FrameBorderSize;
3351 if (border_size > 0.0f)
3352 {
3353 window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, 0, border_size);
3354 window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, 0, border_size);
3355 }
3356}
3357
3359{
3360 ImGuiContext& g = *GImGui;
3361 if (id != g.NavId)
3362 return;
3364 return;
3365 ImGuiWindow* window = g.CurrentWindow;
3366 if (window->DC.NavHideHighlightOneFrame)
3367 return;
3368
3369 float rounding = (flags & ImGuiNavHighlightFlags_NoRounding) ? 0.0f : g.Style.FrameRounding;
3370 ImRect display_rect = bb;
3371 display_rect.ClipWith(window->ClipRect);
3373 {
3374 const float THICKNESS = 2.0f;
3375 const float DISTANCE = 3.0f + THICKNESS * 0.5f;
3376 display_rect.Expand(ImVec2(DISTANCE, DISTANCE));
3377 bool fully_visible = window->ClipRect.Contains(display_rect);
3378 if (!fully_visible)
3379 window->DrawList->PushClipRect(display_rect.Min, display_rect.Max);
3380 window->DrawList->AddRect(display_rect.Min + ImVec2(THICKNESS * 0.5f, THICKNESS * 0.5f), display_rect.Max - ImVec2(THICKNESS * 0.5f, THICKNESS * 0.5f), GetColorU32(ImGuiCol_NavHighlight), rounding, 0, THICKNESS);
3381 if (!fully_visible)
3382 window->DrawList->PopClipRect();
3383 }
3385 {
3386 window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, 0, 1.0f);
3387 }
3388}
3389
3390void ImGui::RenderMouseCursor(ImVec2 base_pos, float base_scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow)
3391{
3392 ImGuiContext& g = *GImGui;
3393 IM_ASSERT(mouse_cursor > ImGuiMouseCursor_None && mouse_cursor < ImGuiMouseCursor_COUNT);
3395 for (int n = 0; n < g.Viewports.Size; n++)
3396 {
3397 // We scale cursor with current viewport/monitor, however Windows 10 for its own hardware cursor seems to be using a different scale factor.
3398 ImVec2 offset, size, uv[4];
3399 if (!font_atlas->GetMouseCursorTexData(mouse_cursor, &offset, &size, &uv[0], &uv[2]))
3400 continue;
3401 ImGuiViewportP* viewport = g.Viewports[n];
3402 const ImVec2 pos = base_pos - offset;
3403 const float scale = base_scale;
3404 if (!viewport->GetMainRect().Overlaps(ImRect(pos, pos + ImVec2(size.x + 2, size.y + 2) * scale)))
3405 continue;
3406 ImDrawList* draw_list = GetForegroundDrawList(viewport);
3407 ImTextureID tex_id = font_atlas->TexID;
3408 draw_list->PushTextureID(tex_id);
3409 draw_list->AddImage(tex_id, pos + ImVec2(1, 0) * scale, pos + (ImVec2(1, 0) + size) * scale, uv[2], uv[3], col_shadow);
3410 draw_list->AddImage(tex_id, pos + ImVec2(2, 0) * scale, pos + (ImVec2(2, 0) + size) * scale, uv[2], uv[3], col_shadow);
3411 draw_list->AddImage(tex_id, pos, pos + size * scale, uv[2], uv[3], col_border);
3412 draw_list->AddImage(tex_id, pos, pos + size * scale, uv[0], uv[1], col_fill);
3413 draw_list->PopTextureID();
3414 }
3415}
3416
3417//-----------------------------------------------------------------------------
3418// [SECTION] INITIALIZATION, SHUTDOWN
3419//-----------------------------------------------------------------------------
3420
3421// Internal state access - if you want to share Dear ImGui state between modules (e.g. DLL) or allocate it yourself
3422// Note that we still point to some static data and members (such as GFontAtlas), so the state instance you end up using will point to the static data within its module
3427
3429{
3430#ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC
3431 IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this.
3432#else
3433 GImGui = ctx;
3434#endif
3435}
3436
3437void ImGui::SetAllocatorFunctions(ImGuiMemAllocFunc alloc_func, ImGuiMemFreeFunc free_func, void* user_data)
3438{
3439 GImAllocatorAllocFunc = alloc_func;
3440 GImAllocatorFreeFunc = free_func;
3441 GImAllocatorUserData = user_data;
3442}
3443
3444// This is provided to facilitate copying allocators from one static/DLL boundary to another (e.g. retrieve default allocator of your executable address space)
3445void ImGui::GetAllocatorFunctions(ImGuiMemAllocFunc* p_alloc_func, ImGuiMemFreeFunc* p_free_func, void** p_user_data)
3446{
3447 *p_alloc_func = GImAllocatorAllocFunc;
3448 *p_free_func = GImAllocatorFreeFunc;
3449 *p_user_data = GImAllocatorUserData;
3450}
3451
3453{
3454 ImGuiContext* prev_ctx = GetCurrentContext();
3455 ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas);
3456 SetCurrentContext(ctx);
3457 Initialize();
3458 if (prev_ctx != NULL)
3459 SetCurrentContext(prev_ctx); // Restore previous context if any, else keep new one.
3460 return ctx;
3461}
3462
3464{
3465 ImGuiContext* prev_ctx = GetCurrentContext();
3466 if (ctx == NULL) //-V1051
3467 ctx = prev_ctx;
3468 SetCurrentContext(ctx);
3469 Shutdown();
3470 SetCurrentContext((prev_ctx != ctx) ? prev_ctx : NULL);
3471 IM_DELETE(ctx);
3472}
3473
3474// IMPORTANT: ###xxx suffixes must be same in ALL languages
3475static const ImGuiLocEntry GLocalizationEntriesEnUS[] =
3476{
3477 { ImGuiLocKey_TableSizeOne, "Size column to fit###SizeOne" },
3478 { ImGuiLocKey_TableSizeAllFit, "Size all columns to fit###SizeAll" },
3479 { ImGuiLocKey_TableSizeAllDefault, "Size all columns to default###SizeAll" },
3480 { ImGuiLocKey_TableResetOrder, "Reset order###ResetOrder" },
3481 { ImGuiLocKey_WindowingMainMenuBar, "(Main menu bar)" },
3482 { ImGuiLocKey_WindowingPopup, "(Popup)" },
3483 { ImGuiLocKey_WindowingUntitled, "(Untitled)" },
3484};
3485
3487{
3488 ImGuiContext& g = *GImGui;
3490
3491 // Add .ini handle for ImGuiWindow and ImGuiTable types
3492 {
3493 ImGuiSettingsHandler ini_handler;
3494 ini_handler.TypeName = "Window";
3495 ini_handler.TypeHash = ImHashStr("Window");
3496 ini_handler.ClearAllFn = WindowSettingsHandler_ClearAll;
3497 ini_handler.ReadOpenFn = WindowSettingsHandler_ReadOpen;
3498 ini_handler.ReadLineFn = WindowSettingsHandler_ReadLine;
3499 ini_handler.ApplyAllFn = WindowSettingsHandler_ApplyAll;
3500 ini_handler.WriteAllFn = WindowSettingsHandler_WriteAll;
3501 AddSettingsHandler(&ini_handler);
3502 }
3504
3505 // Setup default localization table
3506 LocalizeRegisterEntries(GLocalizationEntriesEnUS, IM_ARRAYSIZE(GLocalizationEntriesEnUS));
3507
3508 // Setup default platform clipboard/IME handlers.
3509 g.IO.GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations
3510 g.IO.SetClipboardTextFn = SetClipboardTextFn_DefaultImpl;
3511 g.IO.ClipboardUserData = (void*)&g; // Default implementation use the ImGuiContext as user data (ideally those would be arguments to the function)
3512 g.IO.SetPlatformImeDataFn = SetPlatformImeDataFn_DefaultImpl;
3513
3514 // Create default viewport
3515 ImGuiViewportP* viewport = IM_NEW(ImGuiViewportP)();
3516 g.Viewports.push_back(viewport);
3517 g.TempBuffer.resize(1024 * 3 + 1, 0);
3518
3519#ifdef IMGUI_HAS_DOCK
3520#endif
3521
3522 g.Initialized = true;
3523}
3524
3525// This function is merely here to free heap allocations.
3527{
3528 // The fonts atlas can be used prior to calling NewFrame(), so we clear it even if g.Initialized is FALSE (which would happen if we never called NewFrame)
3529 ImGuiContext& g = *GImGui;
3530 if (g.IO.Fonts && g.FontAtlasOwnedByContext)
3531 {
3532 g.IO.Fonts->Locked = false;
3533 IM_DELETE(g.IO.Fonts);
3534 }
3535 g.IO.Fonts = NULL;
3537
3538 // Cleanup of other data are conditional on actually having initialized Dear ImGui.
3539 if (!g.Initialized)
3540 return;
3541
3542 // Save settings (unless we haven't attempted to load them: CreateContext/DestroyContext without a call to NewFrame shouldn't save an empty file)
3543 if (g.SettingsLoaded && g.IO.IniFilename != NULL)
3545
3547
3548 // Clear everything else
3552 g.CurrentWindow = NULL;
3554 g.WindowsById.Clear();
3555 g.NavWindow = NULL;
3558 g.MovingWindow = NULL;
3559
3561
3562 g.ColorStack.clear();
3563 g.StyleVarStack.clear();
3564 g.FontStack.clear();
3567
3569
3570 g.TabBars.Clear();
3573
3575
3576 g.Tables.Clear();
3579
3583
3586
3587 if (g.LogFile)
3588 {
3589#ifndef IMGUI_DISABLE_TTY_FUNCTIONS
3590 if (g.LogFile != stdout)
3591#endif
3593 g.LogFile = NULL;
3594 }
3595 g.LogBuffer.clear();
3596 g.DebugLogBuf.clear();
3597 g.DebugLogIndex.clear();
3598
3599 g.Initialized = false;
3600}
3601
3602// No specific ordering/dependency support, will see as needed
3604{
3605 ImGuiContext& g = *ctx;
3606 IM_ASSERT(hook->Callback != NULL && hook->HookId == 0 && hook->Type != ImGuiContextHookType_PendingRemoval_);
3607 g.Hooks.push_back(*hook);
3608 g.Hooks.back().HookId = ++g.HookIdNext;
3609 return g.HookIdNext;
3610}
3611
3612// Deferred removal, avoiding issue with changing vector while iterating it
3614{
3615 ImGuiContext& g = *ctx;
3616 IM_ASSERT(hook_id != 0);
3617 for (int n = 0; n < g.Hooks.Size; n++)
3618 if (g.Hooks[n].HookId == hook_id)
3620}
3621
3622// Call context hooks (used by e.g. test engine)
3623// We assume a small number of hooks so all stored in same array
3625{
3626 ImGuiContext& g = *ctx;
3627 for (int n = 0; n < g.Hooks.Size; n++)
3628 if (g.Hooks[n].Type == hook_type)
3629 g.Hooks[n].Callback(&g, &g.Hooks[n]);
3630}
3631
3632
3633//-----------------------------------------------------------------------------
3634// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
3635//-----------------------------------------------------------------------------
3636
3637// ImGuiWindow is mostly a dumb struct. It merely has a constructor and a few helper methods
3638ImGuiWindow::ImGuiWindow(ImGuiContext* ctx, const char* name) : DrawListInst(NULL)
3639{
3640 memset(this, 0, sizeof(*this));
3641 Ctx = ctx;
3642 Name = ImStrdup(name);
3643 NameBufLen = (int)strlen(name) + 1;
3644 ID = ImHashStr(name);
3646 MoveId = GetID("#MOVE");
3647 ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
3648 ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f);
3652 SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX);
3653 LastFrameActive = -1;
3654 LastTimeActive = -1.0f;
3655 FontWindowScale = 1.0f;
3656 SettingsOffset = -1;
3660}
3661
3668
3669ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
3670{
3671 ImGuiID seed = IDStack.back();
3672 ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
3673 ImGuiContext& g = *Ctx;
3674 if (g.DebugHookIdInfo == id)
3676 return id;
3677}
3678
3680{
3681 ImGuiID seed = IDStack.back();
3682 ImGuiID id = ImHashData(&ptr, sizeof(void*), seed);
3683 ImGuiContext& g = *Ctx;
3684 if (g.DebugHookIdInfo == id)
3686 return id;
3687}
3688
3690{
3691 ImGuiID seed = IDStack.back();
3692 ImGuiID id = ImHashData(&n, sizeof(n), seed);
3693 ImGuiContext& g = *Ctx;
3694 if (g.DebugHookIdInfo == id)
3695 ImGui::DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL);
3696 return id;
3697}
3698
3699// This is only used in rare/specific situations to manufacture an ID out of nowhere.
3701{
3702 ImGuiID seed = IDStack.back();
3703 ImRect r_rel = ImGui::WindowRectAbsToRel(this, r_abs);
3704 ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed);
3705 return id;
3706}
3707
3708static void SetCurrentWindow(ImGuiWindow* window)
3709{
3710 ImGuiContext& g = *GImGui;
3711 g.CurrentWindow = window;
3712 g.CurrentTable = window && window->DC.CurrentTableIdx != -1 ? g.Tables.GetByIndex(window->DC.CurrentTableIdx) : NULL;
3713 if (window)
3715}
3716
3724
3725// Free up/compact internal window buffers, we can use this when a window becomes unused.
3726// Not freed:
3727// - ImGuiWindow, ImGuiWindowSettings, Name, StateStorage, ColumnsStorage (may hold useful data)
3728// This should have no noticeable visual effect. When the window reappear however, expect new allocation/buffer growth/copy cost.
3730{
3731 window->MemoryCompacted = true;
3734 window->IDStack.clear();
3735 window->DrawList->_ClearFreeMemory();
3736 window->DC.ChildWindows.clear();
3737 window->DC.ItemWidthStack.clear();
3738 window->DC.TextWrapPosStack.clear();
3739}
3740
3742{
3743 // We stored capacity of the ImDrawList buffer to reduce growth-caused allocation/copy when awakening.
3744 // The other buffers tends to amortize much faster.
3745 window->MemoryCompacted = false;
3749}
3750
3752{
3753 ImGuiContext& g = *GImGui;
3754
3755 // While most behaved code would make an effort to not steal active id during window move/drag operations,
3756 // we at least need to be resilient to it. Cancelling the move is rather aggressive and users of 'master' branch
3757 // may prefer the weird ill-defined half working situation ('docking' did assert), so may need to rework that.
3758 if (g.MovingWindow != NULL && g.ActiveId == g.MovingWindow->MoveId)
3759 {
3760 IMGUI_DEBUG_LOG_ACTIVEID("SetActiveID() cancel MovingWindow\n");
3761 g.MovingWindow = NULL;
3762 }
3763
3764 // Set active id
3765 g.ActiveIdIsJustActivated = (g.ActiveId != id);
3767 {
3768 IMGUI_DEBUG_LOG_ACTIVEID("SetActiveID() old:0x%08X (window \"%s\") -> new:0x%08X (window \"%s\")\n", g.ActiveId, g.ActiveIdWindow ? g.ActiveIdWindow->Name : "", id, window ? window->Name : "");
3769 g.ActiveIdTimer = 0.0f;
3772 g.ActiveIdMouseButton = -1;
3773 if (id != 0)
3774 {
3775 g.LastActiveId = id;
3776 g.LastActiveIdTimer = 0.0f;
3777 }
3778 }
3779 g.ActiveId = id;
3780 g.ActiveIdAllowOverlap = false;
3782 g.ActiveIdWindow = window;
3784 if (id)
3785 {
3786 g.ActiveIdIsAlive = id;
3788 }
3789
3790 // Clear declaration of inputs claimed by the widget
3791 // (Please note that this is WIP and not all keys/inputs are thoroughly declared by all widgets yet)
3792 g.ActiveIdUsingNavDirMask = 0x00;
3794#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
3796#endif
3797}
3798
3800{
3801 SetActiveID(0, NULL); // g.ActiveId = 0;
3802}
3803
3805{
3806 ImGuiContext& g = *GImGui;
3807 g.HoveredId = id;
3808 g.HoveredIdAllowOverlap = false;
3809 if (id != 0 && g.HoveredIdPreviousFrame != id)
3811}
3812
3818
3819// This is called by ItemAdd().
3820// Code not using ItemAdd() may need to call this manually otherwise ActiveId will be cleared. In IMGUI_VERSION_NUM < 18717 this was called by GetID().
3822{
3823 ImGuiContext& g = *GImGui;
3824 if (g.ActiveId == id)
3825 g.ActiveIdIsAlive = id;
3826 if (g.ActiveIdPreviousFrame == id)
3828}
3829
3831{
3832 // This marking is solely to be able to provide info for IsItemDeactivatedAfterEdit().
3833 // ActiveId might have been released by the time we call this (as in the typical press/release button behavior) but still need to fill the data.
3834 ImGuiContext& g = *GImGui;
3835 IM_ASSERT(g.ActiveId == id || g.ActiveId == 0 || g.DragDropActive);
3836 IM_UNUSED(id); // Avoid unused variable warnings when asserts are compiled out.
3837 //IM_ASSERT(g.CurrentWindow->DC.LastItemId == id);
3841}
3842
3843static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags)
3844{
3845 // An active popup disable hovering on other windows (apart from its own children)
3846 // FIXME-OPT: This could be cached/stored within the window.
3847 ImGuiContext& g = *GImGui;
3848 if (g.NavWindow)
3849 if (ImGuiWindow* focused_root_window = g.NavWindow->RootWindow)
3850 if (focused_root_window->WasActive && focused_root_window != window->RootWindow)
3851 {
3852 // For the purpose of those flags we differentiate "standard popup" from "modal popup"
3853 // NB: The 'else' is important because Modal windows are also Popups.
3854 bool want_inhibit = false;
3855 if (focused_root_window->Flags & ImGuiWindowFlags_Modal)
3856 want_inhibit = true;
3857 else if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup))
3858 want_inhibit = true;
3859
3860 // Inhibit hover unless the window is within the stack of our modal/popup
3861 if (want_inhibit)
3862 if (!ImGui::IsWindowWithinBeginStackOf(window->RootWindow, focused_root_window))
3863 return false;
3864 }
3865 return true;
3866}
3867
3868// This is roughly matching the behavior of internal-facing ItemHoverable()
3869// - we allow hovering to be true when ActiveId==window->MoveID, so that clicking on non-interactive items such as a Text() item still returns true with IsItemHovered()
3870// - this should work even for non-interactive items that have no ID, so we cannot use LastItemId
3872{
3873 ImGuiContext& g = *GImGui;
3874 ImGuiWindow* window = g.CurrentWindow;
3876 {
3878 return false;
3879 if (!IsItemFocused())
3880 return false;
3881 }
3882 else
3883 {
3884 // Test for bounding box overlap, as updated as ItemAdd()
3886 if (!(status_flags & ImGuiItemStatusFlags_HoveredRect))
3887 return false;
3889
3890 // Done with rectangle culling so we can perform heavier checks now
3891 // Test if we are hovering the right window (our window could be behind another window)
3892 // [2021/03/02] Reworked / reverted the revert, finally. Note we want e.g. BeginGroup/ItemAdd/EndGroup to work as well. (#3851)
3893 // [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable
3894 // to use IsItemHovered() after EndChild() itself. Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was
3895 // the test that has been running for a long while.
3896 if (g.HoveredWindow != window && (status_flags & ImGuiItemStatusFlags_HoveredWindow) == 0)
3897 if ((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0)
3898 return false;
3899
3900 // Test if another item is active (e.g. being dragged)
3902 if (g.ActiveId != 0 && g.ActiveId != g.LastItemData.ID && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId)
3903 return false;
3904
3905 // Test if interactions on this window are blocked by an active popup or modal.
3906 // The ImGuiHoveredFlags_AllowWhenBlockedByPopup flag will be tested here.
3907 if (!IsWindowContentHoverable(window, flags) && !(g.LastItemData.InFlags & ImGuiItemFlags_NoWindowHoverableCheck))
3908 return false;
3909
3910 // Test if the item is disabled
3912 return false;
3913
3914 // Special handling for calling after Begin() which represent the title bar or tab.
3915 // When the window is skipped/collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case.
3916 if (g.LastItemData.ID == window->MoveId && window->WriteAccessed)
3917 return false;
3918 }
3919
3920 // Handle hover delay
3921 // (some ideas: https://www.nngroup.com/articles/timing-exposing-content)
3922 float delay;
3924 delay = g.IO.HoverDelayNormal;
3925 else if (flags & ImGuiHoveredFlags_DelayShort)
3926 delay = g.IO.HoverDelayShort;
3927 else
3928 delay = 0.0f;
3929 if (delay > 0.0f)
3930 {
3931 ImGuiID hover_delay_id = (g.LastItemData.ID != 0) ? g.LastItemData.ID : window->GetIDFromRectangle(g.LastItemData.Rect);
3932 if ((flags & ImGuiHoveredFlags_NoSharedDelay) && (g.HoverDelayIdPreviousFrame != hover_delay_id))
3933 g.HoverDelayTimer = 0.0f;
3934 g.HoverDelayId = hover_delay_id;
3935 return g.HoverDelayTimer >= delay;
3936 }
3937
3938 return true;
3939}
3940
3941// Internal facing ItemHoverable() used when submitting widgets. Differs slightly from IsItemHovered().
3943{
3944 ImGuiContext& g = *GImGui;
3945 if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap)
3946 return false;
3947
3948 ImGuiWindow* window = g.CurrentWindow;
3949 if (g.HoveredWindow != window)
3950 return false;
3951 if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap)
3952 return false;
3953 if (!IsMouseHoveringRect(bb.Min, bb.Max))
3954 return false;
3955
3956 // Done with rectangle culling so we can perform heavier checks now.
3957 ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags);
3958 if (!(item_flags & ImGuiItemFlags_NoWindowHoverableCheck) && !IsWindowContentHoverable(window, ImGuiHoveredFlags_None))
3959 {
3960 g.HoveredIdDisabled = true;
3961 return false;
3962 }
3963
3964 // We exceptionally allow this function to be called with id==0 to allow using it for easy high-level
3965 // hover test in widgets code. We could also decide to split this function is two.
3966 if (id != 0)
3967 SetHoveredID(id);
3968
3969 // When disabled we'll return false but still set HoveredId
3970 if (item_flags & ImGuiItemFlags_Disabled)
3971 {
3972 // Release active id if turning disabled
3973 if (g.ActiveId == id)
3974 ClearActiveID();
3975 g.HoveredIdDisabled = true;
3976 return false;
3977 }
3978
3979 if (id != 0)
3980 {
3981 // [DEBUG] Item Picker tool!
3982 // We perform the check here because SetHoveredID() is not frequently called (1~ time a frame), making
3983 // the cost of this tool near-zero. We can get slightly better call-stack and support picking non-hovered
3984 // items if we performed the test in ItemAdd(), but that would incur a small runtime cost.
3986 GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(255, 255, 0, 255));
3987 if (g.DebugItemPickerBreakId == id)
3989 }
3990
3992 return false;
3993
3994 return true;
3995}
3996
3997// FIXME: This is inlined/duplicated in ItemAdd()
3999{
4000 ImGuiContext& g = *GImGui;
4001 ImGuiWindow* window = g.CurrentWindow;
4002 if (!bb.Overlaps(window->ClipRect))
4003 if (id == 0 || (id != g.ActiveId && id != g.NavId))
4004 if (!g.LogEnabled)
4005 return true;
4006 return false;
4007}
4008
4009// This is also inlined in ItemAdd()
4010// Note: if ImGuiItemStatusFlags_HasDisplayRect is set, user needs to set g.LastItemData.DisplayRect.
4011void ImGui::SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags item_flags, const ImRect& item_rect)
4012{
4013 ImGuiContext& g = *GImGui;
4014 g.LastItemData.ID = item_id;
4015 g.LastItemData.InFlags = in_flags;
4016 g.LastItemData.StatusFlags = item_flags;
4017 g.LastItemData.Rect = g.LastItemData.NavRect = item_rect;
4018}
4019
4020float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x)
4021{
4022 if (wrap_pos_x < 0.0f)
4023 return 0.0f;
4024
4025 ImGuiContext& g = *GImGui;
4026 ImGuiWindow* window = g.CurrentWindow;
4027 if (wrap_pos_x == 0.0f)
4028 {
4029 // We could decide to setup a default wrapping max point for auto-resizing windows,
4030 // or have auto-wrap (with unspecified wrapping pos) behave as a ContentSize extending function?
4031 //if (window->Hidden && (window->Flags & ImGuiWindowFlags_AlwaysAutoResize))
4032 // wrap_pos_x = ImMax(window->WorkRect.Min.x + g.FontSize * 10.0f, window->WorkRect.Max.x);
4033 //else
4034 wrap_pos_x = window->WorkRect.Max.x;
4035 }
4036 else if (wrap_pos_x > 0.0f)
4037 {
4038 wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space
4039 }
4040
4041 return ImMax(wrap_pos_x - pos.x, 1.0f);
4042}
4043
4044// IM_ALLOC() == ImGui::MemAlloc()
4045void* ImGui::MemAlloc(size_t size)
4046{
4047 if (ImGuiContext* ctx = GImGui)
4048 ctx->IO.MetricsActiveAllocations++;
4049 return (*GImAllocatorAllocFunc)(size, GImAllocatorUserData);
4050}
4051
4052// IM_FREE() == ImGui::MemFree()
4053void ImGui::MemFree(void* ptr)
4054{
4055 if (ptr)
4056 if (ImGuiContext* ctx = GImGui)
4057 ctx->IO.MetricsActiveAllocations--;
4058 return (*GImAllocatorFreeFunc)(ptr, GImAllocatorUserData);
4059}
4060
4062{
4063 ImGuiContext& g = *GImGui;
4065}
4066
4067void ImGui::SetClipboardText(const char* text)
4068{
4069 ImGuiContext& g = *GImGui;
4070 if (g.IO.SetClipboardTextFn)
4072}
4073
4075{
4076 return IMGUI_VERSION;
4077}
4078
4080{
4081 IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
4082 return GImGui->IO;
4083}
4084
4085// Pass this to your backend rendering function! Valid after Render() and until the next call to NewFrame()
4087{
4088 ImGuiContext& g = *GImGui;
4089 ImGuiViewportP* viewport = g.Viewports[0];
4090 return viewport->DrawDataP.Valid ? &viewport->DrawDataP : NULL;
4091}
4092
4094{
4095 return GImGui->Time;
4096}
4097
4099{
4100 return GImGui->FrameCount;
4101}
4102
4103static ImDrawList* GetViewportDrawList(ImGuiViewportP* viewport, size_t drawlist_no, const char* drawlist_name)
4104{
4105 // Create the draw list on demand, because they are not frequently used for all viewports
4106 ImGuiContext& g = *GImGui;
4107 IM_ASSERT(drawlist_no < IM_ARRAYSIZE(viewport->DrawLists));
4108 ImDrawList* draw_list = viewport->DrawLists[drawlist_no];
4109 if (draw_list == NULL)
4110 {
4111 draw_list = IM_NEW(ImDrawList)(&g.DrawListSharedData);
4112 draw_list->_OwnerName = drawlist_name;
4113 viewport->DrawLists[drawlist_no] = draw_list;
4114 }
4115
4116 // Our ImDrawList system requires that there is always a command
4117 if (viewport->DrawListsLastFrame[drawlist_no] != g.FrameCount)
4118 {
4119 draw_list->_ResetForNewFrame();
4120 draw_list->PushTextureID(g.IO.Fonts->TexID);
4121 draw_list->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size, false);
4122 viewport->DrawListsLastFrame[drawlist_no] = g.FrameCount;
4123 }
4124 return draw_list;
4125}
4126
4128{
4129 return GetViewportDrawList((ImGuiViewportP*)viewport, 0, "##Background");
4130}
4131
4137
4139{
4140 return GetViewportDrawList((ImGuiViewportP*)viewport, 1, "##Foreground");
4141}
4142
4148
4153
4155{
4156 // Set ActiveId even if the _NoMove flag is set. Without it, dragging away from a window with _NoMove would activate hover on other windows.
4157 // We _also_ call this when clicking in a window empty space when io.ConfigWindowsMoveFromTitleBarOnly is set, but clear g.MovingWindow afterward.
4158 // This is because we want ActiveId to be set even when the window is not permitted to move.
4159 ImGuiContext& g = *GImGui;
4160 FocusWindow(window);
4161 SetActiveID(window->MoveId, window);
4162 g.NavDisableHighlight = true;
4166
4167 bool can_move_window = true;
4169 can_move_window = false;
4170 if (can_move_window)
4171 g.MovingWindow = window;
4172}
4173
4174// Handle mouse moving window
4175// Note: moving window with the navigation keys (Square + d-pad / CTRL+TAB + Arrows) are processed in NavUpdateWindowing()
4176// FIXME: We don't have strong guarantee that g.MovingWindow stay synched with g.ActiveId == g.MovingWindow->MoveId.
4177// This is currently enforced by the fact that BeginDragDropSource() is setting all g.ActiveIdUsingXXXX flags to inhibit navigation inputs,
4178// but if we should more thoroughly test cases where g.ActiveId or g.MovingWindow gets changed and not the other.
4180{
4181 ImGuiContext& g = *GImGui;
4182 if (g.MovingWindow != NULL)
4183 {
4184 // We actually want to move the root window. g.MovingWindow == window we clicked on (could be a child window).
4185 // We track it to preserve Focus and so that generally ActiveIdWindow == MovingWindow and ActiveId == MovingWindow->MoveId for consistency.
4188 ImGuiWindow* moving_window = g.MovingWindow->RootWindow;
4189 if (g.IO.MouseDown[0] && IsMousePosValid(&g.IO.MousePos))
4190 {
4192 SetWindowPos(moving_window, pos, ImGuiCond_Always);
4194 }
4195 else
4196 {
4197 g.MovingWindow = NULL;
4198 ClearActiveID();
4199 }
4200 }
4201 else
4202 {
4203 // When clicking/dragging from a window that has the _NoMove flag, we still set the ActiveId in order to prevent hovering others.
4205 {
4207 if (!g.IO.MouseDown[0])
4208 ClearActiveID();
4209 }
4210 }
4211}
4212
4213// Initiate moving window when clicking on empty space or title bar.
4214// Handle left-click and right-click focus.
4216{
4217 ImGuiContext& g = *GImGui;
4218 if (g.ActiveId != 0 || g.HoveredId != 0)
4219 return;
4220
4221 // Unless we just made a window/popup appear
4222 if (g.NavWindow && g.NavWindow->Appearing)
4223 return;
4224
4225 // Click on empty space to focus window and start moving
4226 // (after we're done with all our widgets)
4227 if (g.IO.MouseClicked[0])
4228 {
4229 // Handle the edge case of a popup being closed while clicking in its empty space.
4230 // If we try to focus it, FocusWindow() > ClosePopupsOverWindow() will accidentally close any parent popups because they are not linked together any more.
4231 ImGuiWindow* root_window = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL;
4232 const bool is_closed_popup = root_window && (root_window->Flags & ImGuiWindowFlags_Popup) && !IsPopupOpen(root_window->PopupId, ImGuiPopupFlags_AnyPopupLevel);
4233
4234 if (root_window != NULL && !is_closed_popup)
4235 {
4237
4238 // Cancel moving if clicked outside of title bar
4240 if (!root_window->TitleBarRect().Contains(g.IO.MouseClickedPos[0]))
4241 g.MovingWindow = NULL;
4242
4243 // Cancel moving if clicked over an item which was disabled or inhibited by popups (note that we know HoveredId == 0 already)
4244 if (g.HoveredIdDisabled)
4245 g.MovingWindow = NULL;
4246 }
4247 else if (root_window == NULL && g.NavWindow != NULL && GetTopMostPopupModal() == NULL)
4248 {
4249 // Clicking on void disable focus
4250 FocusWindow(NULL);
4251 }
4252 }
4253
4254 // With right mouse button we close popups without changing focus based on where the mouse is aimed
4255 // Instead, focus will be restored to the window under the bottom-most closed popup.
4256 // (The left mouse button path calls FocusWindow on the hovered window, which will lead NewFrame->ClosePopupsOverWindow to trigger)
4257 if (g.IO.MouseClicked[1])
4258 {
4259 // Find the top-most window between HoveredWindow and the top-most Modal Window.
4260 // This is where we can trim the popup stack.
4262 bool hovered_window_above_modal = g.HoveredWindow && (modal == NULL || IsWindowAbove(g.HoveredWindow, modal));
4263 ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal, true);
4264 }
4265}
4266
4267static bool IsWindowActiveAndVisible(ImGuiWindow* window)
4268{
4269 return (window->Active) && (!window->Hidden);
4270}
4271
4272// The reason this is exposed in imgui_internal.h is: on touch-based system that don't have hovering, we want to dispatch inputs to the right target (imgui vs imgui+app)
4274{
4275 ImGuiContext& g = *GImGui;
4276 ImGuiIO& io = g.IO;
4277 g.WindowsHoverPadding = ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_HOVER_PADDING, WINDOWS_HOVER_PADDING));
4278
4279 // Find the window hovered by mouse:
4280 // - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow.
4281 // - When moving a window we can skip the search, which also conveniently bypasses the fact that window->WindowRectClipped is lagging as this point of the frame.
4282 // - We also support the moved window toggling the NoInputs flag after moving has started in order to be able to detect windows below it, which is useful for e.g. docking mechanisms.
4283 bool clear_hovered_windows = false;
4284 FindHoveredWindow();
4285
4286 // Modal windows prevents mouse from hovering behind them.
4287 ImGuiWindow* modal_window = GetTopMostPopupModal();
4288 if (modal_window && g.HoveredWindow && !IsWindowWithinBeginStackOf(g.HoveredWindow->RootWindow, modal_window))
4289 clear_hovered_windows = true;
4290
4291 // Disabled mouse?
4293 clear_hovered_windows = true;
4294
4295 // We track click ownership. When clicked outside of a window the click is owned by the application and
4296 // won't report hovering nor request capture even while dragging over our windows afterward.
4297 const bool has_open_popup = (g.OpenPopupStack.Size > 0);
4298 const bool has_open_modal = (modal_window != NULL);
4299 int mouse_earliest_down = -1;
4300 bool mouse_any_down = false;
4301 for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
4302 {
4303 if (io.MouseClicked[i])
4304 {
4305 io.MouseDownOwned[i] = (g.HoveredWindow != NULL) || has_open_popup;
4306 io.MouseDownOwnedUnlessPopupClose[i] = (g.HoveredWindow != NULL) || has_open_modal;
4307 }
4308 mouse_any_down |= io.MouseDown[i];
4309 if (io.MouseDown[i])
4310 if (mouse_earliest_down == -1 || io.MouseClickedTime[i] < io.MouseClickedTime[mouse_earliest_down])
4311 mouse_earliest_down = i;
4312 }
4313 const bool mouse_avail = (mouse_earliest_down == -1) || io.MouseDownOwned[mouse_earliest_down];
4314 const bool mouse_avail_unless_popup_close = (mouse_earliest_down == -1) || io.MouseDownOwnedUnlessPopupClose[mouse_earliest_down];
4315
4316 // If mouse was first clicked outside of ImGui bounds we also cancel out hovering.
4317 // FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02)
4318 const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0;
4319 if (!mouse_avail && !mouse_dragging_extern_payload)
4320 clear_hovered_windows = true;
4321
4322 if (clear_hovered_windows)
4324
4325 // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to Dear ImGui only, false = dispatch mouse to Dear ImGui + underlying app)
4326 // Update io.WantCaptureMouseAllowPopupClose (experimental) to give a chance for app to react to popup closure with a drag
4327 if (g.WantCaptureMouseNextFrame != -1)
4328 {
4330 }
4331 else
4332 {
4333 io.WantCaptureMouse = (mouse_avail && (g.HoveredWindow != NULL || mouse_any_down)) || has_open_popup;
4334 io.WantCaptureMouseUnlessPopupClose = (mouse_avail_unless_popup_close && (g.HoveredWindow != NULL || mouse_any_down)) || has_open_modal;
4335 }
4336
4337 // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to Dear ImGui only, false = dispatch keyboard info to Dear ImGui + underlying app)
4338 if (g.WantCaptureKeyboardNextFrame != -1)
4340 else
4341 io.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL);
4343 io.WantCaptureKeyboard = true;
4344
4345 // Update io.WantTextInput flag, this is to allow systems without a keyboard (e.g. mobile, hand-held) to show a software keyboard if possible
4346 io.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false;
4347}
4348
4350{
4351 IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
4352 ImGuiContext& g = *GImGui;
4353
4354 // Remove pending delete hooks before frame start.
4355 // This deferred removal avoid issues of removal while iterating the hook vector
4356 for (int n = g.Hooks.Size - 1; n >= 0; n--)
4358 g.Hooks.erase(&g.Hooks[n]);
4359
4361
4362 // Check and assert for various common IO and Configuration mistakes
4363 ErrorCheckNewFrameSanityChecks();
4364
4365 // Load settings on first frame, save settings when modified (after a delay)
4366 UpdateSettings();
4367
4368 g.Time += g.IO.DeltaTime;
4369 g.WithinFrameScope = true;
4370 g.FrameCount += 1;
4372 g.WindowsActiveCount = 0;
4374
4375 // Calculate frame-rate for the user, as a purely luxurious feature
4380 g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)g.FramerateSecPerFrameCount)) : FLT_MAX;
4381
4382 // Process input queue (trickle as many events as possible), turn events into writes to IO structure
4385
4386 // Update viewports (after processing input queue, so io.MouseHoveredViewport is set)
4387 UpdateViewportsNewFrame();
4388
4389 // Setup current font and draw list shared data
4390 g.IO.Fonts->Locked = true;
4392 IM_ASSERT(g.Font->IsLoaded());
4393 ImRect virtual_space(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
4394 for (int n = 0; n < g.Viewports.Size; n++)
4395 virtual_space.Add(g.Viewports[n]->GetMainRect());
4396 g.DrawListSharedData.ClipRectFullscreen = virtual_space.ToVec4();
4400 if (g.Style.AntiAliasedLines)
4404 if (g.Style.AntiAliasedFill)
4408
4409 // Mark rendering data as invalid to prevent user who may have a handle on it to use it.
4410 for (int n = 0; n < g.Viewports.Size; n++)
4411 {
4412 ImGuiViewportP* viewport = g.Viewports[n];
4413 viewport->DrawDataP.Clear();
4414 }
4415
4416 // Drag and drop keep the source ID alive so even if the source disappear our state is consistent
4419
4420 // Update HoveredId data
4422 g.HoveredIdTimer = 0.0f;
4423 if (!g.HoveredIdPreviousFrame || (g.HoveredId && g.ActiveId == g.HoveredId))
4424 g.HoveredIdNotActiveTimer = 0.0f;
4425 if (g.HoveredId)
4427 if (g.HoveredId && g.ActiveId != g.HoveredId)
4430 g.HoveredId = 0;
4431 g.HoveredIdAllowOverlap = false;
4432 g.HoveredIdDisabled = false;
4433
4434 // Clear ActiveID if the item is not alive anymore.
4435 // In 1.87, the common most call to KeepAliveID() was moved from GetID() to ItemAdd().
4436 // As a result, custom widget using ButtonBehavior() _without_ ItemAdd() need to call KeepAliveID() themselves.
4437 if (g.ActiveId != 0 && g.ActiveIdIsAlive != g.ActiveId && g.ActiveIdPreviousFrame == g.ActiveId)
4438 {
4439 IMGUI_DEBUG_LOG_ACTIVEID("NewFrame(): ClearActiveID() because it isn't marked alive anymore!\n");
4440 ClearActiveID();
4441 }
4442
4443 // Update ActiveId data (clear reference to active widget if the widget isn't alive anymore)
4444 if (g.ActiveId)
4445 g.ActiveIdTimer += g.IO.DeltaTime;
4450 g.ActiveIdIsAlive = 0;
4453 g.ActiveIdIsJustActivated = false;
4454 if (g.TempInputId != 0 && g.ActiveId != g.TempInputId)
4455 g.TempInputId = 0;
4456 if (g.ActiveId == 0)
4457 {
4458 g.ActiveIdUsingNavDirMask = 0x00;
4460#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
4462#endif
4463 }
4464
4465#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
4466 if (g.ActiveId == 0)
4468 else if (g.ActiveIdUsingNavInputMask != 0)
4469 {
4470 // If your custom widget code used: { g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel); }
4471 // Since IMGUI_VERSION_NUM >= 18804 it should be: { SetKeyOwner(ImGuiKey_Escape, g.ActiveId); SetKeyOwner(ImGuiKey_NavGamepadCancel, g.ActiveId); }
4475 IM_ASSERT(0); // Other values unsupported
4476 }
4477#endif
4478
4479 // Update hover delay for IsItemHovered() with delays and tooltips
4481 if (g.HoverDelayId != 0)
4482 {
4483 //if (g.IO.MouseDelta.x == 0.0f && g.IO.MouseDelta.y == 0.0f) // Need design/flags
4485 g.HoverDelayClearTimer = 0.0f;
4486 g.HoverDelayId = 0;
4487 }
4488 else if (g.HoverDelayTimer > 0.0f)
4489 {
4490 // This gives a little bit of leeway before clearing the hover timer, allowing mouse to cross gaps
4492 if (g.HoverDelayClearTimer >= ImMax(0.20f, g.IO.DeltaTime * 2.0f)) // ~6 frames at 30 Hz + allow for low framerate
4493 g.HoverDelayTimer = g.HoverDelayClearTimer = 0.0f; // May want a decaying timer, in which case need to clamp at max first, based on max of caller last requested timer.
4494 }
4495
4496 // Drag and drop
4500 g.DragDropWithinSource = false;
4501 g.DragDropWithinTarget = false;
4503
4504 // Close popups on focus lost (currently wip/opt-in)
4505 //if (g.IO.AppFocusLost)
4506 // ClosePopupsExceptModals();
4507
4508 // Update keyboard input state
4509 UpdateKeyboardInputs();
4510
4511 //IM_ASSERT(g.IO.KeyCtrl == IsKeyDown(ImGuiKey_LeftCtrl) || IsKeyDown(ImGuiKey_RightCtrl));
4512 //IM_ASSERT(g.IO.KeyShift == IsKeyDown(ImGuiKey_LeftShift) || IsKeyDown(ImGuiKey_RightShift));
4513 //IM_ASSERT(g.IO.KeyAlt == IsKeyDown(ImGuiKey_LeftAlt) || IsKeyDown(ImGuiKey_RightAlt));
4514 //IM_ASSERT(g.IO.KeySuper == IsKeyDown(ImGuiKey_LeftSuper) || IsKeyDown(ImGuiKey_RightSuper));
4515
4516 // Update gamepad/keyboard navigation
4517 NavUpdate();
4518
4519 // Update mouse input state
4520 UpdateMouseInputs();
4521
4522 // Find hovered window
4523 // (needs to be before UpdateMouseMovingWindowNewFrame so we fill g.HoveredWindowUnderMovingWindow on the mouse release frame)
4525
4526 // Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering)
4528
4529 // Background darkening/whitening
4530 if (GetTopMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f))
4531 g.DimBgRatio = ImMin(g.DimBgRatio + g.IO.DeltaTime * 6.0f, 1.0f);
4532 else
4533 g.DimBgRatio = ImMax(g.DimBgRatio - g.IO.DeltaTime * 10.0f, 0.0f);
4534
4537
4538 // Platform IME data: reset for the frame
4540 g.PlatformImeData.WantVisible = false;
4541
4542 // Mouse wheel scrolling, scale
4543 UpdateMouseWheel();
4544
4545 // Mark all windows as not visible and compact unused memory.
4547 const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer;
4548 for (int i = 0; i != g.Windows.Size; i++)
4549 {
4550 ImGuiWindow* window = g.Windows[i];
4551 window->WasActive = window->Active;
4552 window->Active = false;
4553 window->WriteAccessed = false;
4554 window->BeginCountPreviousFrame = window->BeginCount;
4555 window->BeginCount = 0;
4556
4557 // Garbage collect transient buffers of recently unused windows
4558 if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time)
4560 }
4561
4562 // Garbage collect transient buffers of recently unused tables
4563 for (int i = 0; i < g.TablesLastTimeActive.Size; i++)
4564 if (g.TablesLastTimeActive[i] >= 0.0f && g.TablesLastTimeActive[i] < memory_compact_start_time)
4566 for (int i = 0; i < g.TablesTempData.Size; i++)
4567 if (g.TablesTempData[i].LastTimeActive >= 0.0f && g.TablesTempData[i].LastTimeActive < memory_compact_start_time)
4569 if (g.GcCompactAll)
4571 g.GcCompactAll = false;
4572
4573 // Closing the focused window restore focus to the first active root window in descending z-order
4574 if (g.NavWindow && !g.NavWindow->WasActive)
4575 FocusTopMostWindowUnderOne(NULL, NULL);
4576
4577 // No window should be open at the beginning of the frame.
4578 // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear.
4583 g.GroupStack.resize(0);
4584
4585 // [DEBUG] Update debug features
4586 UpdateDebugToolItemPicker();
4587 UpdateDebugToolStackQueries();
4588 if (g.DebugLocateFrames > 0 && --g.DebugLocateFrames == 0)
4589 g.DebugLocateId = 0;
4591 {
4592 DebugLog("(Auto-disabled ImGuiDebugLogFlags_EventClipper to avoid spamming)\n");
4593 g.DebugLogFlags &= ~ImGuiDebugLogFlags_EventClipper;
4594 }
4595
4596 // Create implicit/fallback window - which we will only render it if the user has added something to it.
4597 // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags.
4598 // This fallback is particularly important as it prevents ImGui:: calls from crashing.
4601 Begin("Debug##Default");
4603
4605}
4606
4607// FIXME: Add a more explicit sort order in the window structure.
4608static int IMGUI_CDECL ChildWindowComparer(const void* lhs, const void* rhs)
4609{
4610 const ImGuiWindow* const a = *(const ImGuiWindow* const *)lhs;
4611 const ImGuiWindow* const b = *(const ImGuiWindow* const *)rhs;
4612 if (int d = (a->Flags & ImGuiWindowFlags_Popup) - (b->Flags & ImGuiWindowFlags_Popup))
4613 return d;
4615 return d;
4617}
4618
4619static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window)
4620{
4621 out_sorted_windows->push_back(window);
4622 if (window->Active)
4623 {
4624 int count = window->DC.ChildWindows.Size;
4625 ImQsort(window->DC.ChildWindows.Data, (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer);
4626 for (int i = 0; i < count; i++)
4627 {
4628 ImGuiWindow* child = window->DC.ChildWindows[i];
4629 if (child->Active)
4630 AddWindowToSortBuffer(out_sorted_windows, child);
4631 }
4632 }
4633}
4634
4635static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* draw_list)
4636{
4637 if (draw_list->CmdBuffer.Size == 0)
4638 return;
4639 if (draw_list->CmdBuffer.Size == 1 && draw_list->CmdBuffer[0].ElemCount == 0 && draw_list->CmdBuffer[0].UserCallback == NULL)
4640 return;
4641
4642 // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc.
4643 // May trigger for you if you are using PrimXXX functions incorrectly.
4644 IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size);
4645 IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size);
4646 if (!(draw_list->Flags & ImDrawListFlags_AllowVtxOffset))
4647 IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size);
4648
4649 // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window)
4650 // If this assert triggers because you are drawing lots of stuff manually:
4651 // - First, make sure you are coarse clipping yourself and not trying to draw many things outside visible bounds.
4652 // Be mindful that the ImDrawList API doesn't filter vertices. Use the Metrics/Debugger window to inspect draw list contents.
4653 // - If you want large meshes with more than 64K vertices, you can either:
4654 // (A) Handle the ImDrawCmd::VtxOffset value in your renderer backend, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'.
4655 // Most example backends already support this from 1.71. Pre-1.71 backends won't.
4656 // Some graphics API such as GL ES 1/2 don't have a way to offset the starting vertex so it is not supported for them.
4657 // (B) Or handle 32-bit indices in your renderer backend, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h.
4658 // Most example backends already support this. For example, the OpenGL example code detect index size at compile-time:
4659 // glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
4660 // Your own engine or render API may use different parameters or function calls to specify index sizes.
4661 // 2 and 4 bytes indices are generally supported by most graphics API.
4662 // - If for some reason neither of those solutions works for you, a workaround is to call BeginChild()/EndChild() before reaching
4663 // the 64K limit to split your draw commands in multiple draw lists.
4664 if (sizeof(ImDrawIdx) == 2)
4665 IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above");
4666
4667 out_list->push_back(draw_list);
4668}
4669
4670static void AddWindowToDrawData(ImGuiWindow* window, int layer)
4671{
4672 ImGuiContext& g = *GImGui;
4673 ImGuiViewportP* viewport = g.Viewports[0];
4675 AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[layer], window->DrawList);
4676 for (int i = 0; i < window->DC.ChildWindows.Size; i++)
4677 {
4678 ImGuiWindow* child = window->DC.ChildWindows[i];
4679 if (IsWindowActiveAndVisible(child)) // Clipped children may have been marked not active
4680 AddWindowToDrawData(child, layer);
4681 }
4682}
4683
4684static inline int GetWindowDisplayLayer(ImGuiWindow* window)
4685{
4686 return (window->Flags & ImGuiWindowFlags_Tooltip) ? 1 : 0;
4687}
4688
4689// Layer is locked for the root window, however child windows may use a different viewport (e.g. extruding menu)
4690static inline void AddRootWindowToDrawData(ImGuiWindow* window)
4691{
4692 AddWindowToDrawData(window, GetWindowDisplayLayer(window));
4693}
4694
4696{
4697 int n = Layers[0].Size;
4698 int size = n;
4699 for (int i = 1; i < IM_ARRAYSIZE(Layers); i++)
4700 size += Layers[i].Size;
4701 Layers[0].resize(size);
4702 for (int layer_n = 1; layer_n < IM_ARRAYSIZE(Layers); layer_n++)
4703 {
4704 ImVector<ImDrawList*>& layer = Layers[layer_n];
4705 if (layer.empty())
4706 continue;
4707 memcpy(&Layers[0][n], &layer[0], layer.Size * sizeof(ImDrawList*));
4708 n += layer.Size;
4709 layer.resize(0);
4710 }
4711}
4712
4713static void SetupViewportDrawData(ImGuiViewportP* viewport, ImVector<ImDrawList*>* draw_lists)
4714{
4715 ImGuiIO& io = ImGui::GetIO();
4716 ImDrawData* draw_data = &viewport->DrawDataP;
4717 draw_data->Valid = true;
4718 draw_data->CmdLists = (draw_lists->Size > 0) ? draw_lists->Data : NULL;
4719 draw_data->CmdListsCount = draw_lists->Size;
4720 draw_data->TotalVtxCount = draw_data->TotalIdxCount = 0;
4721 draw_data->DisplayPos = viewport->Pos;
4722 draw_data->DisplaySize = viewport->Size;
4724 for (int n = 0; n < draw_lists->Size; n++)
4725 {
4726 ImDrawList* draw_list = draw_lists->Data[n];
4727 draw_list->_PopUnusedDrawCmd();
4728 draw_data->TotalVtxCount += draw_list->VtxBuffer.Size;
4729 draw_data->TotalIdxCount += draw_list->IdxBuffer.Size;
4730 }
4731}
4732
4733// Push a clipping rectangle for both ImGui logic (hit-testing etc.) and low-level ImDrawList rendering.
4734// - When using this function it is sane to ensure that float are perfectly rounded to integer values,
4735// so that e.g. (int)(max.x-min.x) in user's render produce correct result.
4736// - If the code here changes, may need to update code of functions like NextColumn() and PushColumnClipRect():
4737// some frequently called functions which to modify both channels and clipping simultaneously tend to use the
4738// more specialized SetWindowClipRectBeforeSetChannel() to avoid extraneous updates of underlying ImDrawCmds.
4739void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect)
4740{
4741 ImGuiWindow* window = GetCurrentWindow();
4742 window->DrawList->PushClipRect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect);
4743 window->ClipRect = window->DrawList->_ClipRectStack.back();
4744}
4745
4747{
4748 ImGuiWindow* window = GetCurrentWindow();
4749 window->DrawList->PopClipRect();
4750 window->ClipRect = window->DrawList->_ClipRectStack.back();
4751}
4752
4753static void ImGui::RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col)
4754{
4755 if ((col & IM_COL32_A_MASK) == 0)
4756 return;
4757
4758 ImGuiViewportP* viewport = (ImGuiViewportP*)GetMainViewport();
4759 ImRect viewport_rect = viewport->GetMainRect();
4760
4761 // Draw behind window by moving the draw command at the FRONT of the draw list
4762 {
4763 // We've already called AddWindowToDrawData() which called DrawList->ChannelsMerge() on DockNodeHost windows,
4764 // and draw list have been trimmed already, hence the explicit recreation of a draw command if missing.
4765 // FIXME: This is creating complication, might be simpler if we could inject a drawlist in drawdata at a given position and not attempt to manipulate ImDrawCmd order.
4766 ImDrawList* draw_list = window->RootWindow->DrawList;
4767 if (draw_list->CmdBuffer.Size == 0)
4768 draw_list->AddDrawCmd();
4769 draw_list->PushClipRect(viewport_rect.Min - ImVec2(1, 1), viewport_rect.Max + ImVec2(1, 1), false); // Ensure ImDrawCmd are not merged
4770 draw_list->AddRectFilled(viewport_rect.Min, viewport_rect.Max, col);
4771 ImDrawCmd cmd = draw_list->CmdBuffer.back();
4772 IM_ASSERT(cmd.ElemCount == 6);
4773 draw_list->CmdBuffer.pop_back();
4774 draw_list->CmdBuffer.push_front(cmd);
4775 draw_list->PopClipRect();
4776 draw_list->AddDrawCmd(); // We need to create a command as CmdBuffer.back().IdxOffset won't be correct if we append to same command.
4777 }
4778}
4779
4781{
4782 ImGuiContext& g = *GImGui;
4783 ImGuiWindow* bottom_most_visible_window = parent_window;
4784 for (int i = FindWindowDisplayIndex(parent_window); i >= 0; i--)
4785 {
4786 ImGuiWindow* window = g.Windows[i];
4787 if (window->Flags & ImGuiWindowFlags_ChildWindow)
4788 continue;
4789 if (!IsWindowWithinBeginStackOf(window, parent_window))
4790 break;
4791 if (IsWindowActiveAndVisible(window) && GetWindowDisplayLayer(window) <= GetWindowDisplayLayer(parent_window))
4792 bottom_most_visible_window = window;
4793 }
4794 return bottom_most_visible_window;
4795}
4796
4797static void ImGui::RenderDimmedBackgrounds()
4798{
4799 ImGuiContext& g = *GImGui;
4800 ImGuiWindow* modal_window = GetTopMostAndVisiblePopupModal();
4801 if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f)
4802 return;
4803 const bool dim_bg_for_modal = (modal_window != NULL);
4804 const bool dim_bg_for_window_list = (g.NavWindowingTargetAnim != NULL && g.NavWindowingTargetAnim->Active);
4805 if (!dim_bg_for_modal && !dim_bg_for_window_list)
4806 return;
4807
4808 if (dim_bg_for_modal)
4809 {
4810 // Draw dimming behind modal or a begin stack child, whichever comes first in draw order.
4811 ImGuiWindow* dim_behind_window = FindBottomMostVisibleWindowWithinBeginStack(modal_window);
4812 RenderDimmedBackgroundBehindWindow(dim_behind_window, GetColorU32(ImGuiCol_ModalWindowDimBg, g.DimBgRatio));
4813 }
4814 else if (dim_bg_for_window_list)
4815 {
4816 // Draw dimming behind CTRL+Tab target window
4817 RenderDimmedBackgroundBehindWindow(g.NavWindowingTargetAnim, GetColorU32(ImGuiCol_NavWindowingDimBg, g.DimBgRatio));
4818
4819 // Draw border around CTRL+Tab target window
4821 ImGuiViewport* viewport = GetMainViewport();
4822 float distance = g.FontSize;
4823 ImRect bb = window->Rect();
4824 bb.Expand(distance);
4825 if (bb.GetWidth() >= viewport->Size.x && bb.GetHeight() >= viewport->Size.y)
4826 bb.Expand(-distance - 1.0f); // If a window fits the entire viewport, adjust its highlight inward
4827 if (window->DrawList->CmdBuffer.Size == 0)
4828 window->DrawList->AddDrawCmd();
4829 window->DrawList->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size);
4831 window->DrawList->PopClipRect();
4832 }
4833}
4834
4835// This is normally called by Render(). You may want to call it directly if you want to avoid calling Render() but the gain will be very minimal.
4837{
4838 ImGuiContext& g = *GImGui;
4840
4841 // Don't process EndFrame() multiple times.
4842 if (g.FrameCountEnded == g.FrameCount)
4843 return;
4844 IM_ASSERT(g.WithinFrameScope && "Forgot to call ImGui::NewFrame()?");
4845
4847
4848 ErrorCheckEndFrameSanityChecks();
4849
4850 // Notify Platform/OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME)
4852 if (g.IO.SetPlatformImeDataFn && memcmp(ime_data, &g.PlatformImeDataPrev, sizeof(ImGuiPlatformImeData)) != 0)
4853 {
4854 IMGUI_DEBUG_LOG_IO("Calling io.SetPlatformImeDataFn(): WantVisible: %d, InputPos (%.2f,%.2f)\n", ime_data->WantVisible, ime_data->InputPos.x, ime_data->InputPos.y);
4855 ImGuiViewport* viewport = GetMainViewport();
4856#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
4857 if (viewport->PlatformHandleRaw == NULL && g.IO.ImeWindowHandle != NULL)
4858 {
4859 viewport->PlatformHandleRaw = g.IO.ImeWindowHandle;
4860 g.IO.SetPlatformImeDataFn(viewport, ime_data);
4861 viewport->PlatformHandleRaw = NULL;
4862 }
4863 else
4864#endif
4865 {
4866 g.IO.SetPlatformImeDataFn(viewport, ime_data);
4867 }
4868 }
4869
4870 // Hide implicit/fallback "Debug" window if it hasn't been used
4873 g.CurrentWindow->Active = false;
4874 End();
4875
4876 // Update navigation: CTRL+Tab, wrap-around requests
4877 NavEndFrame();
4878
4879 // Drag and Drop: Elapse payload (if delivered, or if source stops being submitted)
4880 if (g.DragDropActive)
4881 {
4882 bool is_delivered = g.DragDropPayload.Delivery;
4884 if (is_delivered || is_elapsed)
4885 ClearDragDrop();
4886 }
4887
4888 // Drag and Drop: Fallback for source tooltip. This is not ideal but better than nothing.
4890 {
4891 g.DragDropWithinSource = true;
4892 SetTooltip("...");
4893 g.DragDropWithinSource = false;
4894 }
4895
4896 // End frame
4897 g.WithinFrameScope = false;
4899
4900 // Initiate moving window + handle left-click and right-click focus
4902
4903 // Sort the window list so that all child windows are after their parent
4904 // We cannot do that on FocusWindow() because children may not exist yet
4907 for (int i = 0; i != g.Windows.Size; i++)
4908 {
4909 ImGuiWindow* window = g.Windows[i];
4910 if (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow)) // if a child is active its parent will add it
4911 continue;
4912 AddWindowToSortBuffer(&g.WindowsTempSortBuffer, window);
4913 }
4914
4915 // This usually assert if there is a mismatch between the ImGuiWindowFlags_ChildWindow / ParentWindow values and DC.ChildWindows[] in parents, aka we've done something wrong.
4919
4920 // Unlock font atlas
4921 g.IO.Fonts->Locked = false;
4922
4923 // Clear Input data for next frame
4924 g.IO.AppFocusLost = false;
4925 g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f;
4927
4929}
4930
4931// Prepare the data for rendering so you can call GetDrawData()
4932// (As with anything within the ImGui:: namspace this doesn't touch your GPU or graphics API at all:
4933// it is the role of the ImGui_ImplXXXX_RenderDrawData() function provided by the renderer backend)
4935{
4936 ImGuiContext& g = *GImGui;
4938
4939 if (g.FrameCountEnded != g.FrameCount)
4940 EndFrame();
4941 const bool first_render_of_frame = (g.FrameCountRendered != g.FrameCount);
4944
4946
4947 // Add background ImDrawList (for each active viewport)
4948 for (int n = 0; n != g.Viewports.Size; n++)
4949 {
4950 ImGuiViewportP* viewport = g.Viewports[n];
4951 viewport->DrawDataBuilder.Clear();
4952 if (viewport->DrawLists[0] != NULL)
4953 AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[0], GetBackgroundDrawList(viewport));
4954 }
4955
4956 // Draw modal/window whitening backgrounds
4957 if (first_render_of_frame)
4958 RenderDimmedBackgrounds();
4959
4960 // Add ImDrawList to render
4961 ImGuiWindow* windows_to_render_top_most[2];
4963 windows_to_render_top_most[1] = (g.NavWindowingTarget ? g.NavWindowingListWindow : NULL);
4964 for (int n = 0; n != g.Windows.Size; n++)
4965 {
4966 ImGuiWindow* window = g.Windows[n];
4967 IM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive "warning C6011: Dereferencing NULL pointer 'window'"
4968 if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_top_most[0] && window != windows_to_render_top_most[1])
4969 AddRootWindowToDrawData(window);
4970 }
4971 for (int n = 0; n < IM_ARRAYSIZE(windows_to_render_top_most); n++)
4972 if (windows_to_render_top_most[n] && IsWindowActiveAndVisible(windows_to_render_top_most[n])) // NavWindowingTarget is always temporarily displayed as the top-most window
4973 AddRootWindowToDrawData(windows_to_render_top_most[n]);
4974
4975 // Draw software mouse cursor if requested by io.MouseDrawCursor flag
4976 if (g.IO.MouseDrawCursor && first_render_of_frame && g.MouseCursor != ImGuiMouseCursor_None)
4978
4979 // Setup ImDrawData structures for end-user
4981 for (int n = 0; n < g.Viewports.Size; n++)
4982 {
4983 ImGuiViewportP* viewport = g.Viewports[n];
4985
4986 // Add foreground ImDrawList (for each active viewport)
4987 if (viewport->DrawLists[1] != NULL)
4988 AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[0], GetForegroundDrawList(viewport));
4989
4990 SetupViewportDrawData(viewport, &viewport->DrawDataBuilder.Layers[0]);
4991 ImDrawData* draw_data = &viewport->DrawDataP;
4992 g.IO.MetricsRenderVertices += draw_data->TotalVtxCount;
4993 g.IO.MetricsRenderIndices += draw_data->TotalIdxCount;
4994 }
4995
4997}
4998
4999// Calculate text size. Text can be multi-line. Optionally ignore text after a ## marker.
5000// CalcTextSize("") should return ImVec2(0.0f, g.FontSize)
5001ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width)
5002{
5003 ImGuiContext& g = *GImGui;
5004
5005 const char* text_display_end;
5006 if (hide_text_after_double_hash)
5007 text_display_end = FindRenderedTextEnd(text, text_end); // Hide anything after a '##' string
5008 else
5009 text_display_end = text_end;
5010
5011 ImFont* font = g.Font;
5012 const float font_size = g.FontSize;
5013 if (text == text_display_end)
5014 return ImVec2(0.0f, font_size);
5015 ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL);
5016
5017 // Round
5018 // FIXME: This has been here since Dec 2015 (7b0bf230) but down the line we want this out.
5019 // FIXME: Investigate using ceilf or e.g.
5020 // - https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c
5021 // - https://embarkstudios.github.io/rust-gpu/api/src/libm/math/ceilf.rs.html
5022 text_size.x = IM_FLOOR(text_size.x + 0.99999f);
5023
5024 return text_size;
5025}
5026
5027// Find window given position, search front-to-back
5028// FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programmatically
5029// with SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is
5030// called, aka before the next Begin(). Moving window isn't affected.
5031static void FindHoveredWindow()
5032{
5033 ImGuiContext& g = *GImGui;
5034
5035 ImGuiWindow* hovered_window = NULL;
5036 ImGuiWindow* hovered_window_ignoring_moving_window = NULL;
5038 hovered_window = g.MovingWindow;
5039
5040 ImVec2 padding_regular = g.Style.TouchExtraPadding;
5041 ImVec2 padding_for_resize = g.IO.ConfigWindowsResizeFromEdges ? g.WindowsHoverPadding : padding_regular;
5042 for (int i = g.Windows.Size - 1; i >= 0; i--)
5043 {
5044 ImGuiWindow* window = g.Windows[i];
5045 IM_MSVC_WARNING_SUPPRESS(28182); // [Static Analyzer] Dereferencing NULL pointer.
5046 if (!window->Active || window->Hidden)
5047 continue;
5049 continue;
5050
5051 // Using the clipped AABB, a child window will typically be clipped by its parent (not always)
5052 ImRect bb(window->OuterRectClipped);
5054 bb.Expand(padding_regular);
5055 else
5056 bb.Expand(padding_for_resize);
5057 if (!bb.Contains(g.IO.MousePos))
5058 continue;
5059
5060 // Support for one rectangular hole in any given window
5061 // FIXME: Consider generalizing hit-testing override (with more generic data, callback, etc.) (#1512)
5062 if (window->HitTestHoleSize.x != 0)
5063 {
5064 ImVec2 hole_pos(window->Pos.x + (float)window->HitTestHoleOffset.x, window->Pos.y + (float)window->HitTestHoleOffset.y);
5065 ImVec2 hole_size((float)window->HitTestHoleSize.x, (float)window->HitTestHoleSize.y);
5066 if (ImRect(hole_pos, hole_pos + hole_size).Contains(g.IO.MousePos))
5067 continue;
5068 }
5069
5070 if (hovered_window == NULL)
5071 hovered_window = window;
5072 IM_MSVC_WARNING_SUPPRESS(28182); // [Static Analyzer] Dereferencing NULL pointer.
5073 if (hovered_window_ignoring_moving_window == NULL && (!g.MovingWindow || window->RootWindow != g.MovingWindow->RootWindow))
5074 hovered_window_ignoring_moving_window = window;
5075 if (hovered_window && hovered_window_ignoring_moving_window)
5076 break;
5077 }
5078
5079 g.HoveredWindow = hovered_window;
5080 g.HoveredWindowUnderMovingWindow = hovered_window_ignoring_moving_window;
5081}
5082
5084{
5085 ImGuiContext& g = *GImGui;
5086 if (g.ActiveId)
5087 return g.ActiveId == g.LastItemData.ID;
5088 return false;
5089}
5090
5092{
5093 ImGuiContext& g = *GImGui;
5094 if (g.ActiveId)
5096 return true;
5097 return false;
5098}
5099
5107
5113
5114// == GetItemID() == GetFocusID()
5116{
5117 ImGuiContext& g = *GImGui;
5118 if (g.NavId != g.LastItemData.ID || g.NavId == 0)
5119 return false;
5120 return true;
5121}
5122
5123// Important: this can be useful but it is NOT equivalent to the behavior of e.g.Button()!
5124// Most widgets have specific reactions based on mouse-up/down state, mouse position etc.
5126{
5127 return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_None);
5128}
5129
5131{
5132 ImGuiContext& g = *GImGui;
5133 return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_ToggledOpen) ? true : false;
5134}
5135
5141
5143{
5144 ImGuiContext& g = *GImGui;
5145 return g.HoveredId != 0 || g.HoveredIdPreviousFrame != 0;
5146}
5147
5149{
5150 ImGuiContext& g = *GImGui;
5151 return g.ActiveId != 0;
5152}
5153
5155{
5156 ImGuiContext& g = *GImGui;
5157 return g.NavId != 0 && !g.NavDisableHighlight;
5158}
5159
5165
5171
5172// Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority.
5173// FIXME: Although this is exposed, its interaction and ideal idiom with using ImGuiButtonFlags_AllowItemOverlap flag are extremely confusing, need rework.
5175{
5176 ImGuiContext& g = *GImGui;
5177 ImGuiID id = g.LastItemData.ID;
5178 if (g.HoveredId == id)
5179 g.HoveredIdAllowOverlap = true;
5180 if (g.ActiveId == id)
5181 g.ActiveIdAllowOverlap = true;
5182}
5183
5184// FIXME: It might be undesirable that this will likely disable KeyOwner-aware shortcuts systems. Consider a more fine-tuned version for the two users of this function.
5193
5195{
5196 ImGuiContext& g = *GImGui;
5197 return g.LastItemData.ID;
5198}
5199
5201{
5202 ImGuiContext& g = *GImGui;
5203 return g.LastItemData.Rect.Min;
5204}
5205
5207{
5208 ImGuiContext& g = *GImGui;
5209 return g.LastItemData.Rect.Max;
5210}
5211
5213{
5214 ImGuiContext& g = *GImGui;
5215 return g.LastItemData.Rect.GetSize();
5216}
5217
5218bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags)
5219{
5220 ImGuiContext& g = *GImGui;
5221 ImGuiWindow* parent_window = g.CurrentWindow;
5222
5224 flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove); // Inherit the NoMove flag
5225
5226 // Size
5227 const ImVec2 content_avail = GetContentRegionAvail();
5228 ImVec2 size = ImFloor(size_arg);
5229 const int auto_fit_axises = ((size.x == 0.0f) ? (1 << ImGuiAxis_X) : 0x00) | ((size.y == 0.0f) ? (1 << ImGuiAxis_Y) : 0x00);
5230 if (size.x <= 0.0f)
5231 size.x = ImMax(content_avail.x + size.x, 4.0f); // Arbitrary minimum child size (0.0f causing too many issues)
5232 if (size.y <= 0.0f)
5233 size.y = ImMax(content_avail.y + size.y, 4.0f);
5234 SetNextWindowSize(size);
5235
5236 // Build up name. If you need to append to a same child from multiple location in the ID stack, use BeginChild(ImGuiID id) with a stable value.
5237 const char* temp_window_name;
5238 if (name)
5239 ImFormatStringToTempBuffer(&temp_window_name, NULL, "%s/%s_%08X", parent_window->Name, name, id);
5240 else
5241 ImFormatStringToTempBuffer(&temp_window_name, NULL, "%s/%08X", parent_window->Name, id);
5242
5243 const float backup_border_size = g.Style.ChildBorderSize;
5244 if (!border)
5245 g.Style.ChildBorderSize = 0.0f;
5246 bool ret = Begin(temp_window_name, NULL, flags);
5247 g.Style.ChildBorderSize = backup_border_size;
5248
5249 ImGuiWindow* child_window = g.CurrentWindow;
5250 child_window->ChildId = id;
5251 child_window->AutoFitChildAxises = (ImS8)auto_fit_axises;
5252
5253 // Set the cursor to handle case where the user called SetNextWindowPos()+BeginChild() manually.
5254 // While this is not really documented/defined, it seems that the expected thing to do.
5255 if (child_window->BeginCount == 1)
5256 parent_window->DC.CursorPos = child_window->Pos;
5257
5258 // Process navigation-in immediately so NavInit can run on first frame
5259 if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavHasScroll))
5260 {
5261 FocusWindow(child_window);
5262 NavInitWindow(child_window, false);
5263 SetActiveID(id + 1, child_window); // Steal ActiveId with another arbitrary id so that key-press won't activate child item
5265 }
5266 return ret;
5267}
5268
5269bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
5270{
5271 ImGuiWindow* window = GetCurrentWindow();
5272 return BeginChildEx(str_id, window->GetID(str_id), size_arg, border, extra_flags);
5273}
5274
5275bool ImGui::BeginChild(ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
5276{
5277 IM_ASSERT(id != 0);
5278 return BeginChildEx(NULL, id, size_arg, border, extra_flags);
5279}
5280
5282{
5283 ImGuiContext& g = *GImGui;
5284 ImGuiWindow* window = g.CurrentWindow;
5285
5286 IM_ASSERT(g.WithinEndChild == false);
5287 IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow); // Mismatched BeginChild()/EndChild() calls
5288
5289 g.WithinEndChild = true;
5290 if (window->BeginCount > 1)
5291 {
5292 End();
5293 }
5294 else
5295 {
5296 ImVec2 sz = window->Size;
5297 if (window->AutoFitChildAxises & (1 << ImGuiAxis_X)) // Arbitrary minimum zero-ish child size of 4.0f causes less trouble than a 0.0f
5298 sz.x = ImMax(4.0f, sz.x);
5299 if (window->AutoFitChildAxises & (1 << ImGuiAxis_Y))
5300 sz.y = ImMax(4.0f, sz.y);
5301 End();
5302
5303 ImGuiWindow* parent_window = g.CurrentWindow;
5304 ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz);
5305 ItemSize(sz);
5306 if ((window->DC.NavLayersActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened))
5307 {
5308 ItemAdd(bb, window->ChildId);
5309 RenderNavHighlight(bb, window->ChildId);
5310
5311 // When browsing a window that has no activable items (scroll only) we keep a highlight on the child (pass g.NavId to trick into always displaying)
5312 if (window->DC.NavLayersActiveMask == 0 && window == g.NavWindow)
5314 }
5315 else
5316 {
5317 // Not navigable into
5318 ItemAdd(bb, 0);
5319 }
5320 if (g.HoveredWindow == window)
5322 }
5323 g.WithinEndChild = false;
5324 g.LogLinePosY = -FLT_MAX; // To enforce a carriage return
5325}
5326
5327// Helper to create a child window / scrolling region that looks like a normal widget frame.
5341
5343{
5344 EndChild();
5345}
5346
5347static void SetWindowConditionAllowFlags(ImGuiWindow* window, ImGuiCond flags, bool enabled)
5348{
5349 window->SetWindowPosAllowFlags = enabled ? (window->SetWindowPosAllowFlags | flags) : (window->SetWindowPosAllowFlags & ~flags);
5350 window->SetWindowSizeAllowFlags = enabled ? (window->SetWindowSizeAllowFlags | flags) : (window->SetWindowSizeAllowFlags & ~flags);
5351 window->SetWindowCollapsedAllowFlags = enabled ? (window->SetWindowCollapsedAllowFlags | flags) : (window->SetWindowCollapsedAllowFlags & ~flags);
5352}
5353
5359
5361{
5362 ImGuiID id = ImHashStr(name);
5363 return FindWindowByID(id);
5364}
5365
5366static void ApplyWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* settings)
5367{
5368 window->Pos = ImFloor(ImVec2(settings->Pos.x, settings->Pos.y));
5369 if (settings->Size.x > 0 && settings->Size.y > 0)
5370 window->Size = window->SizeFull = ImFloor(ImVec2(settings->Size.x, settings->Size.y));
5371 window->Collapsed = settings->Collapsed;
5372}
5373
5374static void UpdateWindowInFocusOrderList(ImGuiWindow* window, bool just_created, ImGuiWindowFlags new_flags)
5375{
5376 ImGuiContext& g = *GImGui;
5377
5378 const bool new_is_explicit_child = (new_flags & ImGuiWindowFlags_ChildWindow) != 0 && ((new_flags & ImGuiWindowFlags_Popup) == 0 || (new_flags & ImGuiWindowFlags_ChildMenu) != 0);
5379 const bool child_flag_changed = new_is_explicit_child != window->IsExplicitChild;
5380 if ((just_created || child_flag_changed) && !new_is_explicit_child)
5381 {
5383 g.WindowsFocusOrder.push_back(window);
5384 window->FocusOrder = (short)(g.WindowsFocusOrder.Size - 1);
5385 }
5386 else if (!just_created && child_flag_changed && new_is_explicit_child)
5387 {
5388 IM_ASSERT(g.WindowsFocusOrder[window->FocusOrder] == window);
5389 for (int n = window->FocusOrder + 1; n < g.WindowsFocusOrder.Size; n++)
5390 g.WindowsFocusOrder[n]->FocusOrder--;
5392 window->FocusOrder = -1;
5393 }
5394 window->IsExplicitChild = new_is_explicit_child;
5395}
5396
5397static void InitOrLoadWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* settings)
5398{
5399 // Initial window state with e.g. default/arbitrary window position
5400 // Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window.
5401 const ImGuiViewport* main_viewport = ImGui::GetMainViewport();
5402 window->Pos = main_viewport->Pos + ImVec2(60, 60);
5404
5405 if (settings != NULL)
5406 {
5407 SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false);
5408 ApplyWindowSettings(window, settings);
5409 }
5410 window->DC.CursorStartPos = window->DC.CursorMaxPos = window->DC.IdealMaxPos = window->Pos; // So first call to CalcWindowContentSizes() doesn't return crazy values
5411
5412 if ((window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0)
5413 {
5414 window->AutoFitFramesX = window->AutoFitFramesY = 2;
5415 window->AutoFitOnlyGrows = false;
5416 }
5417 else
5418 {
5419 if (window->Size.x <= 0.0f)
5420 window->AutoFitFramesX = 2;
5421 if (window->Size.y <= 0.0f)
5422 window->AutoFitFramesY = 2;
5423 window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0);
5424 }
5425}
5426
5427static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags)
5428{
5429 // Create window the first time
5430 //IMGUI_DEBUG_LOG("CreateNewWindow '%s', flags = 0x%08X\n", name, flags);
5431 ImGuiContext& g = *GImGui;
5432 ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name);
5433 window->Flags = flags;
5434 g.WindowsById.SetVoidPtr(window->ID, window);
5435
5436 ImGuiWindowSettings* settings = NULL;
5437 if (!(flags & ImGuiWindowFlags_NoSavedSettings))
5438 if ((settings = ImGui::FindWindowSettingsByWindow(window)) != 0)
5439 window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings);
5440
5441 InitOrLoadWindowSettings(window, settings);
5442
5444 g.Windows.push_front(window); // Quite slow but rare and only once
5445 else
5446 g.Windows.push_back(window);
5447
5448 return window;
5449}
5450
5451static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, const ImVec2& size_desired)
5452{
5453 ImGuiContext& g = *GImGui;
5454 ImVec2 new_size = size_desired;
5456 {
5457 // Using -1,-1 on either X/Y axis to preserve the current size.
5459 new_size.x = (cr.Min.x >= 0 && cr.Max.x >= 0) ? ImClamp(new_size.x, cr.Min.x, cr.Max.x) : window->SizeFull.x;
5460 new_size.y = (cr.Min.y >= 0 && cr.Max.y >= 0) ? ImClamp(new_size.y, cr.Min.y, cr.Max.y) : window->SizeFull.y;
5462 {
5465 data.Pos = window->Pos;
5466 data.CurrentSize = window->SizeFull;
5467 data.DesiredSize = new_size;
5469 new_size = data.DesiredSize;
5470 }
5471 new_size.x = IM_FLOOR(new_size.x);
5472 new_size.y = IM_FLOOR(new_size.y);
5473 }
5474
5475 // Minimum size
5477 {
5478 ImGuiWindow* window_for_height = window;
5479 new_size = ImMax(new_size, g.Style.WindowMinSize);
5480 const float minimum_height = window_for_height->TitleBarHeight() + window_for_height->MenuBarHeight() + ImMax(0.0f, g.Style.WindowRounding - 1.0f);
5481 new_size.y = ImMax(new_size.y, minimum_height); // Reduce artifacts with very small windows
5482 }
5483 return new_size;
5484}
5485
5486static void CalcWindowContentSizes(ImGuiWindow* window, ImVec2* content_size_current, ImVec2* content_size_ideal)
5487{
5488 bool preserve_old_content_sizes = false;
5489 if (window->Collapsed && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
5490 preserve_old_content_sizes = true;
5491 else if (window->Hidden && window->HiddenFramesCannotSkipItems == 0 && window->HiddenFramesCanSkipItems > 0)
5492 preserve_old_content_sizes = true;
5493 if (preserve_old_content_sizes)
5494 {
5495 *content_size_current = window->ContentSize;
5496 *content_size_ideal = window->ContentSizeIdeal;
5497 return;
5498 }
5499
5500 content_size_current->x = (window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : IM_FLOOR(window->DC.CursorMaxPos.x - window->DC.CursorStartPos.x);
5501 content_size_current->y = (window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : IM_FLOOR(window->DC.CursorMaxPos.y - window->DC.CursorStartPos.y);
5502 content_size_ideal->x = (window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : IM_FLOOR(ImMax(window->DC.CursorMaxPos.x, window->DC.IdealMaxPos.x) - window->DC.CursorStartPos.x);
5503 content_size_ideal->y = (window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : IM_FLOOR(ImMax(window->DC.CursorMaxPos.y, window->DC.IdealMaxPos.y) - window->DC.CursorStartPos.y);
5504}
5505
5506static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_contents)
5507{
5508 ImGuiContext& g = *GImGui;
5509 ImGuiStyle& style = g.Style;
5510 const float decoration_w_without_scrollbars = window->DecoOuterSizeX1 + window->DecoOuterSizeX2 - window->ScrollbarSizes.x;
5511 const float decoration_h_without_scrollbars = window->DecoOuterSizeY1 + window->DecoOuterSizeY2 - window->ScrollbarSizes.y;
5512 ImVec2 size_pad = window->WindowPadding * 2.0f;
5513 ImVec2 size_desired = size_contents + size_pad + ImVec2(decoration_w_without_scrollbars, decoration_h_without_scrollbars);
5514 if (window->Flags & ImGuiWindowFlags_Tooltip)
5515 {
5516 // Tooltip always resize
5517 return size_desired;
5518 }
5519 else
5520 {
5521 // Maximum window size is determined by the viewport size or monitor size
5522 const bool is_popup = (window->Flags & ImGuiWindowFlags_Popup) != 0;
5523 const bool is_menu = (window->Flags & ImGuiWindowFlags_ChildMenu) != 0;
5524 ImVec2 size_min = style.WindowMinSize;
5525 if (is_popup || is_menu) // Popups and menus bypass style.WindowMinSize by default, but we give then a non-zero minimum size to facilitate understanding problematic cases (e.g. empty popups)
5526 size_min = ImMin(size_min, ImVec2(4.0f, 4.0f));
5527
5528 ImVec2 avail_size = ImGui::GetMainViewport()->WorkSize;
5529 ImVec2 size_auto_fit = ImClamp(size_desired, size_min, ImMax(size_min, avail_size - style.DisplaySafeAreaPadding * 2.0f));
5530
5531 // When the window cannot fit all contents (either because of constraints, either because screen is too small),
5532 // we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding.
5533 ImVec2 size_auto_fit_after_constraint = CalcWindowSizeAfterConstraint(window, size_auto_fit);
5534 bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x - size_pad.x - decoration_w_without_scrollbars < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar);
5535 bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y - size_pad.y - decoration_h_without_scrollbars < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar);
5536 if (will_have_scrollbar_x)
5537 size_auto_fit.y += style.ScrollbarSize;
5538 if (will_have_scrollbar_y)
5539 size_auto_fit.x += style.ScrollbarSize;
5540 return size_auto_fit;
5541 }
5542}
5543
5545{
5546 ImVec2 size_contents_current;
5547 ImVec2 size_contents_ideal;
5548 CalcWindowContentSizes(window, &size_contents_current, &size_contents_ideal);
5549 ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, size_contents_ideal);
5550 ImVec2 size_final = CalcWindowSizeAfterConstraint(window, size_auto_fit);
5551 return size_final;
5552}
5553
5554static ImGuiCol GetWindowBgColorIdx(ImGuiWindow* window)
5555{
5557 return ImGuiCol_PopupBg;
5558 if (window->Flags & ImGuiWindowFlags_ChildWindow)
5559 return ImGuiCol_ChildBg;
5560 return ImGuiCol_WindowBg;
5561}
5562
5563static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& corner_target, const ImVec2& corner_norm, ImVec2* out_pos, ImVec2* out_size)
5564{
5565 ImVec2 pos_min = ImLerp(corner_target, window->Pos, corner_norm); // Expected window upper-left
5566 ImVec2 pos_max = ImLerp(window->Pos + window->Size, corner_target, corner_norm); // Expected window lower-right
5567 ImVec2 size_expected = pos_max - pos_min;
5568 ImVec2 size_constrained = CalcWindowSizeAfterConstraint(window, size_expected);
5569 *out_pos = pos_min;
5570 if (corner_norm.x == 0.0f)
5571 out_pos->x -= (size_constrained.x - size_expected.x);
5572 if (corner_norm.y == 0.0f)
5573 out_pos->y -= (size_constrained.y - size_expected.y);
5574 *out_size = size_constrained;
5575}
5576
5577// Data for resizing from corner
5584static const ImGuiResizeGripDef resize_grip_def[4] =
5585{
5586 { ImVec2(1, 1), ImVec2(-1, -1), 0, 3 }, // Lower-right
5587 { ImVec2(0, 1), ImVec2(+1, -1), 3, 6 }, // Lower-left
5588 { ImVec2(0, 0), ImVec2(+1, +1), 6, 9 }, // Upper-left (Unused)
5589 { ImVec2(1, 0), ImVec2(-1, +1), 9, 12 } // Upper-right (Unused)
5590};
5591
5592// Data for resizing from borders
5599static const ImGuiResizeBorderDef resize_border_def[4] =
5600{
5601 { ImVec2(+1, 0), ImVec2(0, 1), ImVec2(0, 0), IM_PI * 1.00f }, // Left
5602 { ImVec2(-1, 0), ImVec2(1, 0), ImVec2(1, 1), IM_PI * 0.00f }, // Right
5603 { ImVec2(0, +1), ImVec2(0, 0), ImVec2(1, 0), IM_PI * 1.50f }, // Up
5604 { ImVec2(0, -1), ImVec2(1, 1), ImVec2(0, 1), IM_PI * 0.50f } // Down
5605};
5606
5607static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness)
5608{
5609 ImRect rect = window->Rect();
5610 if (thickness == 0.0f)
5611 rect.Max -= ImVec2(1, 1);
5612 if (border_n == ImGuiDir_Left) { return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding); }
5613 if (border_n == ImGuiDir_Right) { return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding); }
5614 if (border_n == ImGuiDir_Up) { return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness); }
5615 if (border_n == ImGuiDir_Down) { return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness); }
5616 IM_ASSERT(0);
5617 return ImRect();
5618}
5619
5620// 0..3: corners (Lower-right, Lower-left, Unused, Unused)
5622{
5623 IM_ASSERT(n >= 0 && n < 4);
5624 ImGuiID id = window->ID;
5625 id = ImHashStr("#RESIZE", 0, id);
5626 id = ImHashData(&n, sizeof(int), id);
5627 return id;
5628}
5629
5630// Borders (Left, Right, Up, Down)
5632{
5633 IM_ASSERT(dir >= 0 && dir < 4);
5634 int n = (int)dir + 4;
5635 ImGuiID id = window->ID;
5636 id = ImHashStr("#RESIZE", 0, id);
5637 id = ImHashData(&n, sizeof(int), id);
5638 return id;
5639}
5640
5641// Handle resize for: Resize Grips, Borders, Gamepad
5642// Return true when using auto-fit (double-click on resize grip)
5643static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect)
5644{
5645 ImGuiContext& g = *GImGui;
5646 ImGuiWindowFlags flags = window->Flags;
5647
5648 if ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
5649 return false;
5650 if (window->WasActive == false) // Early out to avoid running this code for e.g. a hidden implicit/fallback Debug window.
5651 return false;
5652
5653 bool ret_auto_fit = false;
5654 const int resize_border_count = g.IO.ConfigWindowsResizeFromEdges ? 4 : 0;
5655 const float grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f));
5656 const float grip_hover_inner_size = IM_FLOOR(grip_draw_size * 0.75f);
5657 const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_HOVER_PADDING : 0.0f;
5658
5659 ImVec2 pos_target(FLT_MAX, FLT_MAX);
5660 ImVec2 size_target(FLT_MAX, FLT_MAX);
5661
5662 // Resize grips and borders are on layer 1
5664
5665 // Manual resize grips
5666 PushID("#RESIZE");
5667 for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
5668 {
5669 const ImGuiResizeGripDef& def = resize_grip_def[resize_grip_n];
5670 const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, def.CornerPosN);
5671
5672 // Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window
5673 bool hovered, held;
5674 ImRect resize_rect(corner - def.InnerDir * grip_hover_outer_size, corner + def.InnerDir * grip_hover_inner_size);
5675 if (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x);
5676 if (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y);
5677 ImGuiID resize_grip_id = window->GetID(resize_grip_n); // == GetWindowResizeCornerID()
5678 ItemAdd(resize_rect, resize_grip_id, NULL, ImGuiItemFlags_NoNav);
5679 ButtonBehavior(resize_rect, resize_grip_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);
5680 //GetForegroundDrawList(window)->AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255));
5681 if (hovered || held)
5683
5684 if (held && g.IO.MouseClickedCount[0] == 2 && resize_grip_n == 0)
5685 {
5686 // Manual auto-fit when double-clicking
5687 size_target = CalcWindowSizeAfterConstraint(window, size_auto_fit);
5688 ret_auto_fit = true;
5689 ClearActiveID();
5690 }
5691 else if (held)
5692 {
5693 // Resize from any of the four corners
5694 // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position
5695 ImVec2 clamp_min = ImVec2(def.CornerPosN.x == 1.0f ? visibility_rect.Min.x : -FLT_MAX, def.CornerPosN.y == 1.0f ? visibility_rect.Min.y : -FLT_MAX);
5696 ImVec2 clamp_max = ImVec2(def.CornerPosN.x == 0.0f ? visibility_rect.Max.x : +FLT_MAX, def.CornerPosN.y == 0.0f ? visibility_rect.Max.y : +FLT_MAX);
5697 ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(def.InnerDir * grip_hover_outer_size, def.InnerDir * -grip_hover_inner_size, def.CornerPosN); // Corner of the window corresponding to our corner grip
5698 corner_target = ImClamp(corner_target, clamp_min, clamp_max);
5699 CalcResizePosSizeFromAnyCorner(window, corner_target, def.CornerPosN, &pos_target, &size_target);
5700 }
5701
5702 // Only lower-left grip is visible before hovering/activating
5703 if (resize_grip_n == 0 || held || hovered)
5704 resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip);
5705 }
5706 for (int border_n = 0; border_n < resize_border_count; border_n++)
5707 {
5708 const ImGuiResizeBorderDef& def = resize_border_def[border_n];
5709 const ImGuiAxis axis = (border_n == ImGuiDir_Left || border_n == ImGuiDir_Right) ? ImGuiAxis_X : ImGuiAxis_Y;
5710
5711 bool hovered, held;
5712 ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_HOVER_PADDING);
5713 ImGuiID border_id = window->GetID(border_n + 4); // == GetWindowResizeBorderID()
5714 ItemAdd(border_rect, border_id, NULL, ImGuiItemFlags_NoNav);
5715 ButtonBehavior(border_rect, border_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);
5716 //GetForegroundDrawLists(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255));
5717 if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held)
5718 {
5720 if (held)
5721 *border_held = border_n;
5722 }
5723 if (held)
5724 {
5725 ImVec2 clamp_min(border_n == ImGuiDir_Right ? visibility_rect.Min.x : -FLT_MAX, border_n == ImGuiDir_Down ? visibility_rect.Min.y : -FLT_MAX);
5726 ImVec2 clamp_max(border_n == ImGuiDir_Left ? visibility_rect.Max.x : +FLT_MAX, border_n == ImGuiDir_Up ? visibility_rect.Max.y : +FLT_MAX);
5727 ImVec2 border_target = window->Pos;
5728 border_target[axis] = g.IO.MousePos[axis] - g.ActiveIdClickOffset[axis] + WINDOWS_HOVER_PADDING;
5729 border_target = ImClamp(border_target, clamp_min, clamp_max);
5730 CalcResizePosSizeFromAnyCorner(window, border_target, ImMin(def.SegmentN1, def.SegmentN2), &pos_target, &size_target);
5731 }
5732 }
5733 PopID();
5734
5735 // Restore nav layer
5737
5738 // Navigation resize (keyboard/gamepad)
5739 // FIXME: This cannot be moved to NavUpdateWindowing() because CalcWindowSizeAfterConstraint() need to callback into user.
5740 // Not even sure the callback works here.
5741 if (g.NavWindowingTarget && g.NavWindowingTarget->RootWindow == window)
5742 {
5743 ImVec2 nav_resize_dir;
5748 if (nav_resize_dir.x != 0.0f || nav_resize_dir.y != 0.0f)
5749 {
5750 const float NAV_RESIZE_SPEED = 600.0f;
5751 const float resize_step = NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y);
5752 g.NavWindowingAccumDeltaSize += nav_resize_dir * resize_step;
5753 g.NavWindowingAccumDeltaSize = ImMax(g.NavWindowingAccumDeltaSize, visibility_rect.Min - window->Pos - window->Size); // We need Pos+Size >= visibility_rect.Min, so Size >= visibility_rect.Min - Pos, so size_delta >= visibility_rect.Min - window->Pos - window->Size
5754 g.NavWindowingToggleLayer = false;
5755 g.NavDisableMouseHover = true;
5756 resize_grip_col[0] = GetColorU32(ImGuiCol_ResizeGripActive);
5757 ImVec2 accum_floored = ImFloor(g.NavWindowingAccumDeltaSize);
5758 if (accum_floored.x != 0.0f || accum_floored.y != 0.0f)
5759 {
5760 // FIXME-NAV: Should store and accumulate into a separate size buffer to handle sizing constraints properly, right now a constraint will make us stuck.
5761 size_target = CalcWindowSizeAfterConstraint(window, window->SizeFull + accum_floored);
5762 g.NavWindowingAccumDeltaSize -= accum_floored;
5763 }
5764 }
5765 }
5766
5767 // Apply back modified position/size to window
5768 if (size_target.x != FLT_MAX)
5769 {
5770 window->SizeFull = size_target;
5771 MarkIniSettingsDirty(window);
5772 }
5773 if (pos_target.x != FLT_MAX)
5774 {
5775 window->Pos = ImFloor(pos_target);
5776 MarkIniSettingsDirty(window);
5777 }
5778
5779 window->Size = window->SizeFull;
5780 return ret_auto_fit;
5781}
5782
5783static inline void ClampWindowPos(ImGuiWindow* window, const ImRect& visibility_rect)
5784{
5785 ImGuiContext& g = *GImGui;
5786 ImVec2 size_for_clamping = window->Size;
5788 size_for_clamping.y = window->TitleBarHeight();
5789 window->Pos = ImClamp(window->Pos, visibility_rect.Min - size_for_clamping, visibility_rect.Max);
5790}
5791
5792static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window)
5793{
5794 ImGuiContext& g = *GImGui;
5795 float rounding = window->WindowRounding;
5796 float border_size = window->WindowBorderSize;
5797 if (border_size > 0.0f && !(window->Flags & ImGuiWindowFlags_NoBackground))
5798 window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), rounding, 0, border_size);
5799
5800 int border_held = window->ResizeBorderHeld;
5801 if (border_held != -1)
5802 {
5803 const ImGuiResizeBorderDef& def = resize_border_def[border_held];
5804 ImRect border_r = GetResizeBorderRect(window, border_held, rounding, 0.0f);
5805 window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN1) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI * 0.25f, def.OuterAngle);
5806 window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI * 0.25f);
5807 window->DrawList->PathStroke(GetColorU32(ImGuiCol_SeparatorActive), 0, ImMax(2.0f, border_size)); // Thicker than usual
5808 }
5809 if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar))
5810 {
5811 float y = window->Pos.y + window->TitleBarHeight() - 1;
5812 window->DrawList->AddLine(ImVec2(window->Pos.x + border_size, y), ImVec2(window->Pos.x + window->Size.x - border_size, y), GetColorU32(ImGuiCol_Border), g.Style.FrameBorderSize);
5813 }
5814}
5815
5816// Draw background and borders
5817// Draw and handle scrollbars
5818void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, bool handle_borders_and_resize_grips, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size)
5819{
5820 ImGuiContext& g = *GImGui;
5821 ImGuiStyle& style = g.Style;
5822 ImGuiWindowFlags flags = window->Flags;
5823
5824 // Ensure that ScrollBar doesn't read last frame's SkipItems
5825 IM_ASSERT(window->BeginCount == 0);
5826 window->SkipItems = false;
5827
5828 // Draw window + handle manual resize
5829 // As we highlight the title bar when want_focus is set, multiple reappearing windows will have their title bar highlighted on their reappearing frame.
5830 const float window_rounding = window->WindowRounding;
5831 const float window_border_size = window->WindowBorderSize;
5832 if (window->Collapsed)
5833 {
5834 // Title bar only
5835 const float backup_border_size = style.FrameBorderSize;
5837 ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed);
5838 RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding);
5839 g.Style.FrameBorderSize = backup_border_size;
5840 }
5841 else
5842 {
5843 // Window background
5844 if (!(flags & ImGuiWindowFlags_NoBackground))
5845 {
5846 ImU32 bg_col = GetColorU32(GetWindowBgColorIdx(window));
5847 bool override_alpha = false;
5848 float alpha = 1.0f;
5850 {
5851 alpha = g.NextWindowData.BgAlphaVal;
5852 override_alpha = true;
5853 }
5854 if (override_alpha)
5855 bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT);
5856 window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? 0 : ImDrawFlags_RoundCornersBottom);
5857 }
5858
5859 // Title bar
5860 if (!(flags & ImGuiWindowFlags_NoTitleBar))
5861 {
5862 ImU32 title_bar_col = GetColorU32(title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg);
5863 window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawFlags_RoundCornersTop);
5864 }
5865
5866 // Menu bar
5867 if (flags & ImGuiWindowFlags_MenuBar)
5868 {
5869 ImRect menu_bar_rect = window->MenuBarRect();
5870 menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them.
5871 window->DrawList->AddRectFilled(menu_bar_rect.Min + ImVec2(window_border_size, 0), menu_bar_rect.Max - ImVec2(window_border_size, 0), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawFlags_RoundCornersTop);
5872 if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y)
5873 window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize);
5874 }
5875
5876 // Scrollbars
5877 if (window->ScrollbarX)
5879 if (window->ScrollbarY)
5881
5882 // Render resize grips (after their input handling so we don't have a frame of latency)
5883 if (handle_borders_and_resize_grips && !(flags & ImGuiWindowFlags_NoResize))
5884 {
5885 for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
5886 {
5887 const ImU32 col = resize_grip_col[resize_grip_n];
5888 if ((col & IM_COL32_A_MASK) == 0)
5889 continue;
5890 const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
5891 const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN);
5892 window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, window_border_size)));
5893 window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, window_border_size) : ImVec2(window_border_size, resize_grip_draw_size)));
5894 window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12);
5895 window->DrawList->PathFillConvex(col);
5896 }
5897 }
5898
5899 // Borders
5900 if (handle_borders_and_resize_grips)
5901 RenderWindowOuterBorders(window);
5902 }
5903}
5904
5905// Render title text, collapse button, close button
5906void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open)
5907{
5908 ImGuiContext& g = *GImGui;
5909 ImGuiStyle& style = g.Style;
5910 ImGuiWindowFlags flags = window->Flags;
5911
5912 const bool has_close_button = (p_open != NULL);
5913 const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse) && (style.WindowMenuButtonPosition != ImGuiDir_None);
5914
5915 // Close & Collapse button are on the Menu NavLayer and don't default focus (unless there's nothing else on that layer)
5916 // FIXME-NAV: Might want (or not?) to set the equivalent of ImGuiButtonFlags_NoNavFocus so that mouse clicks on standard title bar items don't necessarily set nav/keyboard ref?
5917 const ImGuiItemFlags item_flags_backup = g.CurrentItemFlags;
5920
5921 // Layout buttons
5922 // FIXME: Would be nice to generalize the subtleties expressed here into reusable code.
5923 float pad_l = style.FramePadding.x;
5924 float pad_r = style.FramePadding.x;
5925 float button_sz = g.FontSize;
5926 ImVec2 close_button_pos;
5927 ImVec2 collapse_button_pos;
5928 if (has_close_button)
5929 {
5930 pad_r += button_sz;
5931 close_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y);
5932 }
5933 if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Right)
5934 {
5935 pad_r += button_sz;
5936 collapse_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y);
5937 }
5938 if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Left)
5939 {
5940 collapse_button_pos = ImVec2(title_bar_rect.Min.x + pad_l - style.FramePadding.x, title_bar_rect.Min.y);
5941 pad_l += button_sz;
5942 }
5943
5944 // Collapse button (submitting first so it gets priority when choosing a navigation init fallback)
5945 if (has_collapse_button)
5946 if (CollapseButton(window->GetID("#COLLAPSE"), collapse_button_pos))
5947 window->WantCollapseToggle = true; // Defer actual collapsing to next frame as we are too far in the Begin() function
5948
5949 // Close button
5950 if (has_close_button)
5951 if (CloseButton(window->GetID("#CLOSE"), close_button_pos))
5952 *p_open = false;
5953
5955 g.CurrentItemFlags = item_flags_backup;
5956
5957 // Title bar text (with: horizontal alignment, avoiding collapse/close button, optional "unsaved document" marker)
5958 // FIXME: Refactor text alignment facilities along with RenderText helpers, this is WAY too much messy code..
5959 const float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? button_sz * 0.80f : 0.0f;
5960 const ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f);
5961
5962 // As a nice touch we try to ensure that centered title text doesn't get affected by visibility of Close/Collapse button,
5963 // while uncentered title text will still reach edges correctly.
5964 if (pad_l > style.FramePadding.x)
5965 pad_l += g.Style.ItemInnerSpacing.x;
5966 if (pad_r > style.FramePadding.x)
5967 pad_r += g.Style.ItemInnerSpacing.x;
5968 if (style.WindowTitleAlign.x > 0.0f && style.WindowTitleAlign.x < 1.0f)
5969 {
5970 float centerness = ImSaturate(1.0f - ImFabs(style.WindowTitleAlign.x - 0.5f) * 2.0f); // 0.0f on either edges, 1.0f on center
5971 float pad_extend = ImMin(ImMax(pad_l, pad_r), title_bar_rect.GetWidth() - pad_l - pad_r - text_size.x);
5972 pad_l = ImMax(pad_l, pad_extend * centerness);
5973 pad_r = ImMax(pad_r, pad_extend * centerness);
5974 }
5975
5976 ImRect layout_r(title_bar_rect.Min.x + pad_l, title_bar_rect.Min.y, title_bar_rect.Max.x - pad_r, title_bar_rect.Max.y);
5977 ImRect clip_r(layout_r.Min.x, layout_r.Min.y, ImMin(layout_r.Max.x + g.Style.ItemInnerSpacing.x, title_bar_rect.Max.x), layout_r.Max.y);
5979 {
5980 ImVec2 marker_pos;
5981 marker_pos.x = ImClamp(layout_r.Min.x + (layout_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x + text_size.x, layout_r.Min.x, layout_r.Max.x);
5982 marker_pos.y = (layout_r.Min.y + layout_r.Max.y) * 0.5f;
5983 if (marker_pos.x > layout_r.Min.x)
5984 {
5985 RenderBullet(window->DrawList, marker_pos, GetColorU32(ImGuiCol_Text));
5986 clip_r.Max.x = ImMin(clip_r.Max.x, marker_pos.x - (int)(marker_size_x * 0.5f));
5987 }
5988 }
5989 //if (g.IO.KeyShift) window->DrawList->AddRect(layout_r.Min, layout_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG]
5990 //if (g.IO.KeyCtrl) window->DrawList->AddRect(clip_r.Min, clip_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG]
5991 RenderTextClipped(layout_r.Min, layout_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_r);
5992}
5993
5995{
5996 window->ParentWindow = parent_window;
5997 window->RootWindow = window->RootWindowPopupTree = window->RootWindowForTitleBarHighlight = window->RootWindowForNav = window;
5998 if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip))
5999 window->RootWindow = parent_window->RootWindow;
6000 if (parent_window && (flags & ImGuiWindowFlags_Popup))
6001 window->RootWindowPopupTree = parent_window->RootWindowPopupTree;
6002 if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)))
6005 {
6006 IM_ASSERT(window->RootWindowForNav->ParentWindow != NULL);
6008 }
6009}
6010
6011// When a modal popup is open, newly created windows that want focus (i.e. are not popups and do not specify ImGuiWindowFlags_NoFocusOnAppearing)
6012// should be positioned behind that modal window, unless the window was created inside the modal begin-stack.
6013// In case of multiple stacked modals newly created window honors begin stack order and does not go below its own modal parent.
6014// - Window // FindBlockingModal() returns Modal1
6015// - Window // .. returns Modal1
6016// - Modal1 // .. returns Modal2
6017// - Window // .. returns Modal2
6018// - Window // .. returns Modal2
6019// - Modal2 // .. returns Modal2
6020static ImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window)
6021{
6022 ImGuiContext& g = *GImGui;
6023 if (g.OpenPopupStack.Size <= 0)
6024 return NULL;
6025
6026 // Find a modal that has common parent with specified window. Specified window should be positioned behind that modal.
6027 for (int i = g.OpenPopupStack.Size - 1; i >= 0; i--)
6028 {
6029 ImGuiWindow* popup_window = g.OpenPopupStack.Data[i].Window;
6030 if (popup_window == NULL || !(popup_window->Flags & ImGuiWindowFlags_Modal))
6031 continue;
6032 if (!popup_window->Active && !popup_window->WasActive) // Check WasActive, because this code may run before popup renders on current frame, also check Active to handle newly created windows.
6033 continue;
6034 if (IsWindowWithinBeginStackOf(window, popup_window)) // Window is rendered over last modal, no render order change needed.
6035 break;
6036 for (ImGuiWindow* parent = popup_window->ParentWindowInBeginStack->RootWindow; parent != NULL; parent = parent->ParentWindowInBeginStack->RootWindow)
6037 if (IsWindowWithinBeginStackOf(window, parent))
6038 return popup_window; // Place window above its begin stack parent.
6039 }
6040 return NULL;
6041}
6042
6043// Push a new Dear ImGui window to add widgets to.
6044// - A default window called "Debug" is automatically stacked at the beginning of every frame so you can use widgets without explicitly calling a Begin/End pair.
6045// - Begin/End can be called multiple times during the frame with the same window name to append content.
6046// - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file).
6047// You can use the "##" or "###" markers to use the same label with different id, or same id with different label. See documentation at the top of this file.
6048// - Return false when window is collapsed, so you can early out in your code. You always need to call ImGui::End() even if false is returned.
6049// - Passing 'bool* p_open' displays a Close button on the upper-right corner of the window, the pointed value will be set to false when the button is pressed.
6050bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
6051{
6052 ImGuiContext& g = *GImGui;
6053 const ImGuiStyle& style = g.Style;
6054 IM_ASSERT(name != NULL && name[0] != '\0'); // Window name required
6055 IM_ASSERT(g.WithinFrameScope); // Forgot to call ImGui::NewFrame()
6056 IM_ASSERT(g.FrameCountEnded != g.FrameCount); // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet
6057
6058 // Find or create
6059 ImGuiWindow* window = FindWindowByName(name);
6060 const bool window_just_created = (window == NULL);
6061 if (window_just_created)
6062 window = CreateNewWindow(name, flags);
6063
6064 // Automatically disable manual moving/resizing when NoInputs is set
6067
6070
6071 const int current_frame = g.FrameCount;
6072 const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame);
6074
6075 // Update the Appearing flag
6076 bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1); // Not using !WasActive because the implicit "Debug" window would always toggle off->on
6077 if (flags & ImGuiWindowFlags_Popup)
6078 {
6080 window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed
6081 window_just_activated_by_user |= (window != popup_ref.Window);
6082 }
6083 window->Appearing = window_just_activated_by_user;
6084 if (window->Appearing)
6085 SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true);
6086
6087 // Update Flags, LastFrameActive, BeginOrderXXX fields
6088 if (first_begin_of_the_frame)
6089 {
6090 UpdateWindowInFocusOrderList(window, window_just_created, flags);
6091 window->Flags = (ImGuiWindowFlags)flags;
6092 window->LastFrameActive = current_frame;
6093 window->LastTimeActive = (float)g.Time;
6094 window->BeginOrderWithinParent = 0;
6095 window->BeginOrderWithinContext = (short)(g.WindowsActiveCount++);
6096 }
6097 else
6098 {
6099 flags = window->Flags;
6100 }
6101
6102 // Parent window is latched only on the first call to Begin() of the frame, so further append-calls can be done from a different window stack
6103 ImGuiWindow* parent_window_in_stack = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back().Window;
6104 ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow;
6105 IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow));
6106
6107 // We allow window memory to be compacted so recreate the base stack when needed.
6108 if (window->IDStack.Size == 0)
6109 window->IDStack.push_back(window->ID);
6110
6111 // Add to stack
6112 // We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow()
6113 g.CurrentWindow = window;
6114 ImGuiWindowStackData window_stack_data;
6115 window_stack_data.Window = window;
6116 window_stack_data.ParentLastItemDataBackup = g.LastItemData;
6117 window_stack_data.StackSizesOnBegin.SetToContextState(&g);
6118 g.CurrentWindowStack.push_back(window_stack_data);
6119 if (flags & ImGuiWindowFlags_ChildMenu)
6120 g.BeginMenuCount++;
6121
6122 // Update ->RootWindow and others pointers (before any possible call to FocusWindow)
6123 if (first_begin_of_the_frame)
6124 {
6125 UpdateWindowParentAndRootLinks(window, flags, parent_window);
6126 window->ParentWindowInBeginStack = parent_window_in_stack;
6127 }
6128
6129 // Add to focus scope stack
6130 PushFocusScope(window->ID);
6132 g.CurrentWindow = NULL;
6133
6134 // Add to popup stack
6135 if (flags & ImGuiWindowFlags_Popup)
6136 {
6138 popup_ref.Window = window;
6139 popup_ref.ParentNavLayer = parent_window_in_stack->DC.NavLayerCurrent;
6140 g.BeginPopupStack.push_back(popup_ref);
6141 window->PopupId = popup_ref.PopupId;
6142 }
6143
6144 // Process SetNextWindow***() calls
6145 // (FIXME: Consider splitting the HasXXX flags into X/Y components
6146 bool window_pos_set_by_api = false;
6147 bool window_size_x_set_by_api = false, window_size_y_set_by_api = false;
6149 {
6150 window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) != 0;
6151 if (window_pos_set_by_api && ImLengthSqr(g.NextWindowData.PosPivotVal) > 0.00001f)
6152 {
6153 // May be processed on the next frame if this is our first frame and we are measuring size
6154 // FIXME: Look into removing the branch so everything can go through this same code path for consistency.
6158 }
6159 else
6160 {
6162 }
6163 }
6165 {
6166 window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f);
6167 window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f);
6169 }
6171 {
6172 if (g.NextWindowData.ScrollVal.x >= 0.0f)
6173 {
6175 window->ScrollTargetCenterRatio.x = 0.0f;
6176 }
6177 if (g.NextWindowData.ScrollVal.y >= 0.0f)
6178 {
6180 window->ScrollTargetCenterRatio.y = 0.0f;
6181 }
6182 }
6185 else if (first_begin_of_the_frame)
6186 window->ContentSizeExplicit = ImVec2(0.0f, 0.0f);
6190 FocusWindow(window);
6191 if (window->Appearing)
6192 SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false);
6193
6194 // When reusing window again multiple times a frame, just append content (don't need to setup again)
6195 if (first_begin_of_the_frame)
6196 {
6197 // Initialize
6198 const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior of Child+Tooltip for pinned tooltip (#1345)
6199 const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesCannotSkipItems > 0);
6200 window->Active = true;
6201 window->HasCloseButton = (p_open != NULL);
6202 window->ClipRect = ImVec4(-FLT_MAX, -FLT_MAX, +FLT_MAX, +FLT_MAX);
6203 window->IDStack.resize(1);
6204 window->DrawList->_ResetForNewFrame();
6205 window->DC.CurrentTableIdx = -1;
6206
6207 // Restore buffer capacity when woken from a compacted state, to avoid
6208 if (window->MemoryCompacted)
6210
6211 // Update stored window name when it changes (which can _only_ happen with the "###" operator, so the ID would stay unchanged).
6212 // The title bar always display the 'name' parameter, so we only update the string storage if it needs to be visible to the end-user elsewhere.
6213 bool window_title_visible_elsewhere = false;
6214 if (g.NavWindowingListWindow != NULL && (window->Flags & ImGuiWindowFlags_NoNavFocus) == 0) // Window titles visible when using CTRL+TAB
6215 window_title_visible_elsewhere = true;
6216 if (window_title_visible_elsewhere && !window_just_created && strcmp(name, window->Name) != 0)
6217 {
6218 size_t buf_len = (size_t)window->NameBufLen;
6219 window->Name = ImStrdupcpy(window->Name, &buf_len, name);
6220 window->NameBufLen = (int)buf_len;
6221 }
6222
6223 // UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS
6224
6225 // Update contents size from last frame for auto-fitting (or use explicit size)
6226 CalcWindowContentSizes(window, &window->ContentSize, &window->ContentSizeIdeal);
6227 if (window->HiddenFramesCanSkipItems > 0)
6228 window->HiddenFramesCanSkipItems--;
6229 if (window->HiddenFramesCannotSkipItems > 0)
6231 if (window->HiddenFramesForRenderOnly > 0)
6232 window->HiddenFramesForRenderOnly--;
6233
6234 // Hide new windows for one frame until they calculate their size
6235 if (window_just_created && (!window_size_x_set_by_api || !window_size_y_set_by_api))
6236 window->HiddenFramesCannotSkipItems = 1;
6237
6238 // Hide popup/tooltip window when re-opening while we measure size (because we recycle the windows)
6239 // We reset Size/ContentSize for reappearing popups/tooltips early in this function, so further code won't be tempted to use the old size.
6240 if (window_just_activated_by_user && (flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0)
6241 {
6242 window->HiddenFramesCannotSkipItems = 1;
6244 {
6245 if (!window_size_x_set_by_api)
6246 window->Size.x = window->SizeFull.x = 0.f;
6247 if (!window_size_y_set_by_api)
6248 window->Size.y = window->SizeFull.y = 0.f;
6249 window->ContentSize = window->ContentSizeIdeal = ImVec2(0.f, 0.f);
6250 }
6251 }
6252
6253 // SELECT VIEWPORT
6254 // FIXME-VIEWPORT: In the docking/viewport branch, this is the point where we select the current viewport (which may affect the style)
6255
6256 ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)GetMainViewport();
6257 SetWindowViewport(window, viewport);
6258 SetCurrentWindow(window);
6259
6260 // LOCK BORDER SIZE AND PADDING FOR THE FRAME (so that altering them doesn't cause inconsistencies)
6261
6262 if (flags & ImGuiWindowFlags_ChildWindow)
6263 window->WindowBorderSize = style.ChildBorderSize;
6264 else
6266 window->WindowPadding = style.WindowPadding;
6268 window->WindowPadding = ImVec2(0.0f, (flags & ImGuiWindowFlags_MenuBar) ? style.WindowPadding.y : 0.0f);
6269
6270 // Lock menu offset so size calculation can use it as menu-bar windows need a minimum size.
6271 window->DC.MenuBarOffset.x = ImMax(ImMax(window->WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x);
6273
6274 bool use_current_size_for_scrollbar_x = window_just_created;
6275 bool use_current_size_for_scrollbar_y = window_just_created;
6276
6277 // Collapse window by double-clicking on title bar
6278 // At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing
6279 if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse))
6280 {
6281 // We don't use a regular button+id to test for double-click on title bar (mostly due to legacy reason, could be fixed), so verify that we don't have items over the title bar.
6282 ImRect title_bar_rect = window->TitleBarRect();
6283 if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) && g.IO.MouseClickedCount[0] == 2)
6284 window->WantCollapseToggle = true;
6285 if (window->WantCollapseToggle)
6286 {
6287 window->Collapsed = !window->Collapsed;
6288 if (!window->Collapsed)
6289 use_current_size_for_scrollbar_y = true;
6290 MarkIniSettingsDirty(window);
6291 }
6292 }
6293 else
6294 {
6295 window->Collapsed = false;
6296 }
6297 window->WantCollapseToggle = false;
6298
6299 // SIZE
6300
6301 // Outer Decoration Sizes
6302 // (we need to clear ScrollbarSize immediatly as CalcWindowAutoFitSize() needs it and can be called from other locations).
6303 const ImVec2 scrollbar_sizes_from_last_frame = window->ScrollbarSizes;
6304 window->DecoOuterSizeX1 = 0.0f;
6305 window->DecoOuterSizeX2 = 0.0f;
6306 window->DecoOuterSizeY1 = window->TitleBarHeight() + window->MenuBarHeight();
6307 window->DecoOuterSizeY2 = 0.0f;
6308 window->ScrollbarSizes = ImVec2(0.0f, 0.0f);
6309
6310 // Calculate auto-fit size, handle automatic resize
6311 const ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSizeIdeal);
6312 if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed)
6313 {
6314 // Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc.
6315 if (!window_size_x_set_by_api)
6316 {
6317 window->SizeFull.x = size_auto_fit.x;
6318 use_current_size_for_scrollbar_x = true;
6319 }
6320 if (!window_size_y_set_by_api)
6321 {
6322 window->SizeFull.y = size_auto_fit.y;
6323 use_current_size_for_scrollbar_y = true;
6324 }
6325 }
6326 else if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
6327 {
6328 // Auto-fit may only grow window during the first few frames
6329 // We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed.
6330 if (!window_size_x_set_by_api && window->AutoFitFramesX > 0)
6331 {
6332 window->SizeFull.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x;
6333 use_current_size_for_scrollbar_x = true;
6334 }
6335 if (!window_size_y_set_by_api && window->AutoFitFramesY > 0)
6336 {
6337 window->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y;
6338 use_current_size_for_scrollbar_y = true;
6339 }
6340 if (!window->Collapsed)
6341 MarkIniSettingsDirty(window);
6342 }
6343
6344 // Apply minimum/maximum window size constraints and final size
6345 window->SizeFull = CalcWindowSizeAfterConstraint(window, window->SizeFull);
6346 window->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull;
6347
6348 // POSITION
6349
6350 // Popup latch its initial position, will position itself when it appears next frame
6351 if (window_just_activated_by_user)
6352 {
6354 if ((flags & ImGuiWindowFlags_Popup) != 0 && !(flags & ImGuiWindowFlags_Modal) && !window_pos_set_by_api) // FIXME: BeginPopup() could use SetNextWindowPos()
6355 window->Pos = g.BeginPopupStack.back().OpenPopupPos;
6356 }
6357
6358 // Position child window
6359 if (flags & ImGuiWindowFlags_ChildWindow)
6360 {
6361 IM_ASSERT(parent_window && parent_window->Active);
6362 window->BeginOrderWithinParent = (short)parent_window->DC.ChildWindows.Size;
6363 parent_window->DC.ChildWindows.push_back(window);
6364 if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip)
6365 window->Pos = parent_window->DC.CursorPos;
6366 }
6367
6368 const bool window_pos_with_pivot = (window->SetWindowPosVal.x != FLT_MAX && window->HiddenFramesCannotSkipItems == 0);
6369 if (window_pos_with_pivot)
6370 SetWindowPos(window, window->SetWindowPosVal - window->Size * window->SetWindowPosPivot, 0); // Position given a pivot (e.g. for centering)
6371 else if ((flags & ImGuiWindowFlags_ChildMenu) != 0)
6372 window->Pos = FindBestWindowPosForPopup(window);
6373 else if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api && window_just_appearing_after_hidden_for_resize)
6374 window->Pos = FindBestWindowPosForPopup(window);
6375 else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip)
6376 window->Pos = FindBestWindowPosForPopup(window);
6377
6378 // Calculate the range of allowed position for that window (to be movable and visible past safe area padding)
6379 // When clamping to stay visible, we will enforce that window->Pos stays inside of visibility_rect.
6380 ImRect viewport_rect(viewport->GetMainRect());
6381 ImRect viewport_work_rect(viewport->GetWorkRect());
6382 ImVec2 visibility_padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding);
6383 ImRect visibility_rect(viewport_work_rect.Min + visibility_padding, viewport_work_rect.Max - visibility_padding);
6384
6385 // Clamp position/size so window stays visible within its viewport or monitor
6386 // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing.
6387 if (!window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow))
6388 if (viewport_rect.GetWidth() > 0.0f && viewport_rect.GetHeight() > 0.0f)
6389 ClampWindowPos(window, visibility_rect);
6390 window->Pos = ImFloor(window->Pos);
6391
6392 // Lock window rounding for the frame (so that altering them doesn't cause inconsistencies)
6393 // Large values tend to lead to variety of artifacts and are not recommended.
6394 window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding;
6395
6396 // For windows with title bar or menu bar, we clamp to FrameHeight(FontSize + FramePadding.y * 2.0f) to completely hide artifacts.
6397 //if ((window->Flags & ImGuiWindowFlags_MenuBar) || !(window->Flags & ImGuiWindowFlags_NoTitleBar))
6398 // window->WindowRounding = ImMin(window->WindowRounding, g.FontSize + style.FramePadding.y * 2.0f);
6399
6400 // Apply window focus (new and reactivated windows are moved to front)
6401 bool want_focus = false;
6402 if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing))
6403 {
6404 if (flags & ImGuiWindowFlags_Popup)
6405 want_focus = true;
6406 else if ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) == 0)
6407 want_focus = true;
6408
6410 if (modal != NULL && !IsWindowWithinBeginStackOf(window, modal))
6411 {
6412 // Avoid focusing a window that is created outside of active modal. This will prevent active modal from being closed.
6413 // Since window is not focused it would reappear at the same display position like the last time it was visible.
6414 // In case of completely new windows it would go to the top (over current modal), but input to such window would still be blocked by modal.
6415 // Position window behind a modal that is not a begin-parent of this window.
6416 want_focus = false;
6417 if (window == window->RootWindow)
6418 {
6419 ImGuiWindow* blocking_modal = FindBlockingModal(window);
6420 IM_ASSERT(blocking_modal != NULL);
6421 BringWindowToDisplayBehind(window, blocking_modal);
6422 }
6423 }
6424 }
6425
6426 // [Test Engine] Register whole window in the item system (before submitting further decorations)
6427#ifdef IMGUI_ENABLE_TEST_ENGINE
6428 if (g.TestEngineHookItems)
6429 {
6430 IM_ASSERT(window->IDStack.Size == 1);
6431 window->IDStack.Size = 0; // As window->IDStack[0] == window->ID here, make sure TestEngine doesn't erroneously see window as parent of itself.
6432 IMGUI_TEST_ENGINE_ITEM_ADD(window->ID, window->Rect(), NULL);
6434 window->IDStack.Size = 1;
6435 }
6436#endif
6437
6438 // Handle manual resize: Resize Grips, Borders, Gamepad
6439 int border_held = -1;
6440 ImU32 resize_grip_col[4] = {};
6441 const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it.
6442 const float resize_grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.10f, window->WindowRounding + 1.0f + g.FontSize * 0.2f));
6443 if (!window->Collapsed)
6444 if (UpdateWindowManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0], visibility_rect))
6445 use_current_size_for_scrollbar_x = use_current_size_for_scrollbar_y = true;
6446 window->ResizeBorderHeld = (signed char)border_held;
6447
6448 // SCROLLBAR VISIBILITY
6449
6450 // Update scrollbar visibility (based on the Size that was effective during last frame or the auto-resized Size).
6451 if (!window->Collapsed)
6452 {
6453 // When reading the current size we need to read it after size constraints have been applied.
6454 // Intentionally use previous frame values for InnerRect and ScrollbarSizes.
6455 // And when we use window->DecorationUp here it doesn't have ScrollbarSizes.y applied yet.
6456 ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - (window->DecoOuterSizeY1 + window->DecoOuterSizeY2));
6457 ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + scrollbar_sizes_from_last_frame;
6458 ImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0, 0) : window->ContentSize + window->WindowPadding * 2.0f;
6459 float size_x_for_scrollbars = use_current_size_for_scrollbar_x ? avail_size_from_current_frame.x : avail_size_from_last_frame.x;
6460 float size_y_for_scrollbars = use_current_size_for_scrollbar_y ? avail_size_from_current_frame.y : avail_size_from_last_frame.y;
6461 //bool scrollbar_y_from_last_frame = window->ScrollbarY; // FIXME: May want to use that in the ScrollbarX expression? How many pros vs cons?
6462 window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar));
6463 window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((needed_size_from_last_frame.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar));
6464 if (window->ScrollbarX && !window->ScrollbarY)
6465 window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar);
6466 window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f);
6467
6468 // Amend the partially filled window->DecorationXXX values.
6469 window->DecoOuterSizeX2 += window->ScrollbarSizes.x;
6470 window->DecoOuterSizeY2 += window->ScrollbarSizes.y;
6471 }
6472
6473 // UPDATE RECTANGLES (1- THOSE NOT AFFECTED BY SCROLLING)
6474 // Update various regions. Variables they depend on should be set above in this function.
6475 // We set this up after processing the resize grip so that our rectangles doesn't lag by a frame.
6476
6477 // Outer rectangle
6478 // Not affected by window border size. Used by:
6479 // - FindHoveredWindow() (w/ extra padding when border resize is enabled)
6480 // - Begin() initial clipping rect for drawing window background and borders.
6481 // - Begin() clipping whole child
6482 const ImRect host_rect = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) ? parent_window->ClipRect : viewport_rect;
6483 const ImRect outer_rect = window->Rect();
6484 const ImRect title_bar_rect = window->TitleBarRect();
6485 window->OuterRectClipped = outer_rect;
6486 window->OuterRectClipped.ClipWith(host_rect);
6487
6488 // Inner rectangle
6489 // Not affected by window border size. Used by:
6490 // - InnerClipRect
6491 // - ScrollToRectEx()
6492 // - NavUpdatePageUpPageDown()
6493 // - Scrollbar()
6494 window->InnerRect.Min.x = window->Pos.x + window->DecoOuterSizeX1;
6495 window->InnerRect.Min.y = window->Pos.y + window->DecoOuterSizeY1;
6496 window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->DecoOuterSizeX2;
6497 window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->DecoOuterSizeY2;
6498
6499 // Inner clipping rectangle.
6500 // Will extend a little bit outside the normal work region.
6501 // This is to allow e.g. Selectable or CollapsingHeader or some separators to cover that space.
6502 // Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result.
6503 // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior.
6504 // Affected by window/frame border size. Used by:
6505 // - Begin() initial clip rect
6506 float top_border_size = (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize);
6507 window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize));
6508 window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y + top_border_size);
6509 window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize));
6510 window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y - window->WindowBorderSize);
6511 window->InnerClipRect.ClipWithFull(host_rect);
6512
6513 // Default item width. Make it proportional to window size if window manually resizes
6514 if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize))
6515 window->ItemWidthDefault = ImFloor(window->Size.x * 0.65f);
6516 else
6517 window->ItemWidthDefault = ImFloor(g.FontSize * 16.0f);
6518
6519 // SCROLLING
6520
6521 // Lock down maximum scrolling
6522 // The value of ScrollMax are ahead from ScrollbarX/ScrollbarY which is intentionally using InnerRect from previous rect in order to accommodate
6523 // for right/bottom aligned items without creating a scrollbar.
6524 window->ScrollMax.x = ImMax(0.0f, window->ContentSize.x + window->WindowPadding.x * 2.0f - window->InnerRect.GetWidth());
6525 window->ScrollMax.y = ImMax(0.0f, window->ContentSize.y + window->WindowPadding.y * 2.0f - window->InnerRect.GetHeight());
6526
6527 // Apply scrolling
6528 window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window);
6529 window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
6530 window->DecoInnerSizeX1 = window->DecoInnerSizeY1 = 0.0f;
6531
6532 // DRAWING
6533
6534 // Setup draw list and outer clipping rectangle
6535 IM_ASSERT(window->DrawList->CmdBuffer.Size == 1 && window->DrawList->CmdBuffer[0].ElemCount == 0);
6537 PushClipRect(host_rect.Min, host_rect.Max, false);
6538
6539 // Child windows can render their decoration (bg color, border, scrollbars, etc.) within their parent to save a draw call (since 1.71)
6540 // When using overlapping child windows, this will break the assumption that child z-order is mapped to submission order.
6541 // FIXME: User code may rely on explicit sorting of overlapping child window and would need to disable this somehow. Please get in contact if you are affected (github #4493)
6542 {
6543 bool render_decorations_in_parent = false;
6544 if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip)
6545 {
6546 // - We test overlap with the previous child window only (testing all would end up being O(log N) not a good investment here)
6547 // - We disable this when the parent window has zero vertices, which is a common pattern leading to laying out multiple overlapping childs
6548 ImGuiWindow* previous_child = parent_window->DC.ChildWindows.Size >= 2 ? parent_window->DC.ChildWindows[parent_window->DC.ChildWindows.Size - 2] : NULL;
6549 bool previous_child_overlapping = previous_child ? previous_child->Rect().Overlaps(window->Rect()) : false;
6550 bool parent_is_empty = parent_window->DrawList->VtxBuffer.Size > 0;
6551 if (window->DrawList->CmdBuffer.back().ElemCount == 0 && parent_is_empty && !previous_child_overlapping)
6552 render_decorations_in_parent = true;
6553 }
6554 if (render_decorations_in_parent)
6555 window->DrawList = parent_window->DrawList;
6556
6557 // Handle title bar, scrollbar, resize grips and resize borders
6558 const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow;
6559 const bool title_bar_is_highlight = want_focus || (window_to_highlight && window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight);
6560 const bool handle_borders_and_resize_grips = true; // This exists to facilitate merge with 'docking' branch.
6561 RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, handle_borders_and_resize_grips, resize_grip_count, resize_grip_col, resize_grip_draw_size);
6562
6563 if (render_decorations_in_parent)
6564 window->DrawList = &window->DrawListInst;
6565 }
6566
6567 // UPDATE RECTANGLES (2- THOSE AFFECTED BY SCROLLING)
6568
6569 // Work rectangle.
6570 // Affected by window padding and border size. Used by:
6571 // - Columns() for right-most edge
6572 // - TreeNode(), CollapsingHeader() for right-most edge
6573 // - BeginTabBar() for right-most edge
6574 const bool allow_scrollbar_x = !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar);
6575 const bool allow_scrollbar_y = !(flags & ImGuiWindowFlags_NoScrollbar);
6576 const float work_rect_size_x = (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : ImMax(allow_scrollbar_x ? window->ContentSize.x : 0.0f, window->Size.x - window->WindowPadding.x * 2.0f - (window->DecoOuterSizeX1 + window->DecoOuterSizeX2)));
6577 const float work_rect_size_y = (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : ImMax(allow_scrollbar_y ? window->ContentSize.y : 0.0f, window->Size.y - window->WindowPadding.y * 2.0f - (window->DecoOuterSizeY1 + window->DecoOuterSizeY2)));
6578 window->WorkRect.Min.x = ImFloor(window->InnerRect.Min.x - window->Scroll.x + ImMax(window->WindowPadding.x, window->WindowBorderSize));
6579 window->WorkRect.Min.y = ImFloor(window->InnerRect.Min.y - window->Scroll.y + ImMax(window->WindowPadding.y, window->WindowBorderSize));
6580 window->WorkRect.Max.x = window->WorkRect.Min.x + work_rect_size_x;
6581 window->WorkRect.Max.y = window->WorkRect.Min.y + work_rect_size_y;
6582 window->ParentWorkRect = window->WorkRect;
6583
6584 // [LEGACY] Content Region
6585 // FIXME-OBSOLETE: window->ContentRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it.
6586 // Used by:
6587 // - Mouse wheel scrolling + many other things
6588 window->ContentRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x + window->DecoOuterSizeX1;
6589 window->ContentRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + window->DecoOuterSizeY1;
6590 window->ContentRegionRect.Max.x = window->ContentRegionRect.Min.x + (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : (window->Size.x - window->WindowPadding.x * 2.0f - (window->DecoOuterSizeX1 + window->DecoOuterSizeX2)));
6591 window->ContentRegionRect.Max.y = window->ContentRegionRect.Min.y + (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : (window->Size.y - window->WindowPadding.y * 2.0f - (window->DecoOuterSizeY1 + window->DecoOuterSizeY2)));
6592
6593 // Setup drawing context
6594 // (NB: That term "drawing context / DC" lost its meaning a long time ago. Initially was meant to hold transient data only. Nowadays difference between window-> and window->DC-> is dubious.)
6595 window->DC.Indent.x = window->DecoOuterSizeX1 + window->WindowPadding.x - window->Scroll.x;
6596 window->DC.GroupOffset.x = 0.0f;
6597 window->DC.ColumnsOffset.x = 0.0f;
6598
6599 // Record the loss of precision of CursorStartPos which can happen due to really large scrolling amount.
6600 // This is used by clipper to compensate and fix the most common use case of large scroll area. Easy and cheap, next best thing compared to switching everything to double or ImU64.
6601 double start_pos_highp_x = (double)window->Pos.x + window->WindowPadding.x - (double)window->Scroll.x + window->DecoOuterSizeX1 + window->DC.ColumnsOffset.x;
6602 double start_pos_highp_y = (double)window->Pos.y + window->WindowPadding.y - (double)window->Scroll.y + window->DecoOuterSizeY1;
6603 window->DC.CursorStartPos = ImVec2((float)start_pos_highp_x, (float)start_pos_highp_y);
6604 window->DC.CursorStartPosLossyness = ImVec2((float)(start_pos_highp_x - window->DC.CursorStartPos.x), (float)(start_pos_highp_y - window->DC.CursorStartPos.y));
6605 window->DC.CursorPos = window->DC.CursorStartPos;
6606 window->DC.CursorPosPrevLine = window->DC.CursorPos;
6607 window->DC.CursorMaxPos = window->DC.CursorStartPos;
6608 window->DC.IdealMaxPos = window->DC.CursorStartPos;
6609 window->DC.CurrLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f);
6610 window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f;
6611 window->DC.IsSameLine = window->DC.IsSetPos = false;
6612
6615 window->DC.NavLayersActiveMaskNext = 0x00;
6616 window->DC.NavHideHighlightOneFrame = false;
6617 window->DC.NavHasScroll = (window->ScrollMax.y > 0.0f);
6618
6619 window->DC.MenuBarAppending = false;
6620 window->DC.MenuColumns.Update(style.ItemSpacing.x, window_just_activated_by_user);
6621 window->DC.TreeDepth = 0;
6622 window->DC.TreeJumpToParentOnPopMask = 0x00;
6623 window->DC.ChildWindows.resize(0);
6624 window->DC.StateStorage = &window->StateStorage;
6625 window->DC.CurrentColumns = NULL;
6627 window->DC.ParentLayoutType = parent_window ? parent_window->DC.LayoutType : ImGuiLayoutType_Vertical;
6628
6629 window->DC.ItemWidth = window->ItemWidthDefault;
6630 window->DC.TextWrapPos = -1.0f; // disabled
6631 window->DC.ItemWidthStack.resize(0);
6632 window->DC.TextWrapPosStack.resize(0);
6633
6634 if (window->AutoFitFramesX > 0)
6635 window->AutoFitFramesX--;
6636 if (window->AutoFitFramesY > 0)
6637 window->AutoFitFramesY--;
6638
6639 // Apply focus (we need to call FocusWindow() AFTER setting DC.CursorStartPos so our initial navigation reference rectangle can start around there)
6640 if (want_focus)
6641 {
6642 FocusWindow(window);
6643 NavInitWindow(window, false); // <-- this is in the way for us to be able to defer and sort reappearing FocusWindow() calls
6644 }
6645
6646 // Title bar
6647 if (!(flags & ImGuiWindowFlags_NoTitleBar))
6648 RenderWindowTitleBarContents(window, ImRect(title_bar_rect.Min.x + window->WindowBorderSize, title_bar_rect.Min.y, title_bar_rect.Max.x - window->WindowBorderSize, title_bar_rect.Max.y), name, p_open);
6649
6650 // Clear hit test shape every frame
6651 window->HitTestHoleSize.x = window->HitTestHoleSize.y = 0;
6652
6653 // Pressing CTRL+C while holding on a window copy its content to the clipboard
6654 // This works but 1. doesn't handle multiple Begin/End pairs, 2. recursing into another Begin/End pair - so we need to work that out and add better logging scope.
6655 // Maybe we can support CTRL+C on every element?
6656 /*
6657 //if (g.NavWindow == window && g.ActiveId == 0)
6658 if (g.ActiveId == window->MoveId)
6659 if (g.IO.KeyCtrl && IsKeyPressed(ImGuiKey_C))
6660 LogToClipboard();
6661 */
6662
6663 // We fill last item data based on Title Bar/Tab, in order for IsItemHovered() and IsItemActive() to be usable after Begin().
6664 // This is useful to allow creating context menus on title bar only, etc.
6665 SetLastItemData(window->MoveId, g.CurrentItemFlags, IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0, title_bar_rect);
6666
6667 // [DEBUG]
6668#ifndef IMGUI_DISABLE_DEBUG_TOOLS
6669 if (g.DebugLocateId != 0 && (window->ID == g.DebugLocateId || window->MoveId == g.DebugLocateId))
6671#endif
6672
6673 // [Test Engine] Register title bar / tab with MoveId.
6674#ifdef IMGUI_ENABLE_TEST_ENGINE
6675 if (!(window->Flags & ImGuiWindowFlags_NoTitleBar))
6677#endif
6678 }
6679 else
6680 {
6681 // Append
6682 SetCurrentWindow(window);
6683 }
6684
6685 PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true);
6686
6687 // Clear 'accessed' flag last thing (After PushClipRect which will set the flag. We want the flag to stay false when the default "Debug" window is unused)
6688 window->WriteAccessed = false;
6689 window->BeginCount++;
6691
6692 // Update visibility
6693 if (first_begin_of_the_frame)
6694 {
6695 if (flags & ImGuiWindowFlags_ChildWindow)
6696 {
6697 // Child window can be out of sight and have "negative" clip windows.
6698 // Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar).
6699 IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0);
6700 if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) // FIXME: Doesn't make sense for ChildWindow??
6701 {
6702 const bool nav_request = (flags & ImGuiWindowFlags_NavFlattened) && (g.NavAnyRequest && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav);
6703 if (!g.LogEnabled && !nav_request)
6704 if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y)
6705 window->HiddenFramesCanSkipItems = 1;
6706 }
6707
6708 // Hide along with parent or if parent is collapsed
6709 if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCanSkipItems > 0))
6710 window->HiddenFramesCanSkipItems = 1;
6711 if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCannotSkipItems > 0))
6712 window->HiddenFramesCannotSkipItems = 1;
6713 }
6714
6715 // Don't render if style alpha is 0.0 at the time of Begin(). This is arbitrary and inconsistent but has been there for a long while (may remove at some point)
6716 if (style.Alpha <= 0.0f)
6717 window->HiddenFramesCanSkipItems = 1;
6718
6719 // Update the Hidden flag
6720 bool hidden_regular = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0);
6721 window->Hidden = hidden_regular || (window->HiddenFramesForRenderOnly > 0);
6722
6723 // Disable inputs for requested number of frames
6724 if (window->DisableInputsFrames > 0)
6725 {
6726 window->DisableInputsFrames--;
6728 }
6729
6730 // Update the SkipItems flag, used to early out of all items functions (no layout required)
6731 bool skip_items = false;
6732 if (window->Collapsed || !window->Active || hidden_regular)
6733 if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesCannotSkipItems <= 0)
6734 skip_items = true;
6735 window->SkipItems = skip_items;
6736 }
6737
6738 return !window->SkipItems;
6739}
6740
6742{
6743 ImGuiContext& g = *GImGui;
6744 ImGuiWindow* window = g.CurrentWindow;
6745
6746 // Error checking: verify that user hasn't called End() too many times!
6748 {
6749 IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size > 1, "Calling End() too many times!");
6750 return;
6751 }
6753
6754 // Error checking: verify that user doesn't directly call End() on a child window.
6755 if (window->Flags & ImGuiWindowFlags_ChildWindow)
6756 IM_ASSERT_USER_ERROR(g.WithinEndChild, "Must call EndChild() and not End()!");
6757
6758 // Close anything that is open
6759 if (window->DC.CurrentColumns)
6760 EndColumns();
6761 PopClipRect(); // Inner window clip rectangle
6762 PopFocusScope();
6763
6764 // Stop logging
6765 if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) // FIXME: add more options for scope of logging
6766 LogFinish();
6767
6768 if (window->DC.IsSetPos)
6770
6771 // Pop from window stack
6773 if (window->Flags & ImGuiWindowFlags_ChildMenu)
6774 g.BeginMenuCount--;
6775 if (window->Flags & ImGuiWindowFlags_Popup)
6779 SetCurrentWindow(g.CurrentWindowStack.Size == 0 ? NULL : g.CurrentWindowStack.back().Window);
6780}
6781
6783{
6784 ImGuiContext& g = *GImGui;
6785 IM_ASSERT(window == window->RootWindow);
6786
6787 const int cur_order = window->FocusOrder;
6788 IM_ASSERT(g.WindowsFocusOrder[cur_order] == window);
6789 if (g.WindowsFocusOrder.back() == window)
6790 return;
6791
6792 const int new_order = g.WindowsFocusOrder.Size - 1;
6793 for (int n = cur_order; n < new_order; n++)
6794 {
6795 g.WindowsFocusOrder[n] = g.WindowsFocusOrder[n + 1];
6796 g.WindowsFocusOrder[n]->FocusOrder--;
6797 IM_ASSERT(g.WindowsFocusOrder[n]->FocusOrder == n);
6798 }
6799 g.WindowsFocusOrder[new_order] = window;
6800 window->FocusOrder = (short)new_order;
6801}
6802
6804{
6805 ImGuiContext& g = *GImGui;
6806 ImGuiWindow* current_front_window = g.Windows.back();
6807 if (current_front_window == window || current_front_window->RootWindow == window) // Cheap early out (could be better)
6808 return;
6809 for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the top-most window
6810 if (g.Windows[i] == window)
6811 {
6812 memmove(&g.Windows[i], &g.Windows[i + 1], (size_t)(g.Windows.Size - i - 1) * sizeof(ImGuiWindow*));
6813 g.Windows[g.Windows.Size - 1] = window;
6814 break;
6815 }
6816}
6817
6819{
6820 ImGuiContext& g = *GImGui;
6821 if (g.Windows[0] == window)
6822 return;
6823 for (int i = 0; i < g.Windows.Size; i++)
6824 if (g.Windows[i] == window)
6825 {
6826 memmove(&g.Windows[1], &g.Windows[0], (size_t)i * sizeof(ImGuiWindow*));
6827 g.Windows[0] = window;
6828 break;
6829 }
6830}
6831
6833{
6834 IM_ASSERT(window != NULL && behind_window != NULL);
6835 ImGuiContext& g = *GImGui;
6836 window = window->RootWindow;
6837 behind_window = behind_window->RootWindow;
6838 int pos_wnd = FindWindowDisplayIndex(window);
6839 int pos_beh = FindWindowDisplayIndex(behind_window);
6840 if (pos_wnd < pos_beh)
6841 {
6842 size_t copy_bytes = (pos_beh - pos_wnd - 1) * sizeof(ImGuiWindow*);
6843 memmove(&g.Windows.Data[pos_wnd], &g.Windows.Data[pos_wnd + 1], copy_bytes);
6844 g.Windows[pos_beh - 1] = window;
6845 }
6846 else
6847 {
6848 size_t copy_bytes = (pos_wnd - pos_beh) * sizeof(ImGuiWindow*);
6849 memmove(&g.Windows.Data[pos_beh + 1], &g.Windows.Data[pos_beh], copy_bytes);
6850 g.Windows[pos_beh] = window;
6851 }
6852}
6853
6855{
6856 ImGuiContext& g = *GImGui;
6857 return g.Windows.index_from_ptr(g.Windows.find(window));
6858}
6859
6860// Moving window to front of display and set focus (which happens to be back of our sorted list)
6862{
6863 ImGuiContext& g = *GImGui;
6864
6865 if (g.NavWindow != window)
6866 {
6867 SetNavWindow(window);
6868 if (window && g.NavDisableMouseHover)
6869 g.NavMousePosDirty = true;
6870 g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId
6872 g.NavFocusScopeId = window ? window->NavRootFocusScopeId : 0;
6873 g.NavIdIsAlive = false;
6874
6875 // Close popups if any
6876 ClosePopupsOverWindow(window, false);
6877 }
6878
6879 // Move the root window to the top of the pile
6880 IM_ASSERT(window == NULL || window->RootWindow != NULL);
6881 ImGuiWindow* focus_front_window = window ? window->RootWindow : NULL; // NB: In docking branch this is window->RootWindowDockStop
6882 ImGuiWindow* display_front_window = window ? window->RootWindow : NULL;
6883
6884 // Steal active widgets. Some of the cases it triggers includes:
6885 // - Focus a window while an InputText in another window is active, if focus happens before the old InputText can run.
6886 // - When using Nav to activate menu items (due to timing of activating on press->new window appears->losing ActiveId)
6887 if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != focus_front_window)
6889 ClearActiveID();
6890
6891 // Passing NULL allow to disable keyboard focus
6892 if (!window)
6893 return;
6894
6895 // Bring to front
6896 BringWindowToFocusFront(focus_front_window);
6897 if (((window->Flags | display_front_window->Flags) & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0)
6898 BringWindowToDisplayFront(display_front_window);
6899}
6900
6901void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window)
6902{
6903 ImGuiContext& g = *GImGui;
6904 int start_idx = g.WindowsFocusOrder.Size - 1;
6905 if (under_this_window != NULL)
6906 {
6907 // Aim at root window behind us, if we are in a child window that's our own root (see #4640)
6908 int offset = -1;
6909 while (under_this_window->Flags & ImGuiWindowFlags_ChildWindow)
6910 {
6911 under_this_window = under_this_window->ParentWindow;
6912 offset = 0;
6913 }
6914 start_idx = FindWindowFocusIndex(under_this_window) + offset;
6915 }
6916 for (int i = start_idx; i >= 0; i--)
6917 {
6918 // We may later decide to test for different NoXXXInputs based on the active navigation input (mouse vs nav) but that may feel more confusing to the user.
6919 ImGuiWindow* window = g.WindowsFocusOrder[i];
6920 IM_ASSERT(window == window->RootWindow);
6921 if (window != ignore_window && window->WasActive)
6923 {
6924 ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(window);
6925 FocusWindow(focus_window);
6926 return;
6927 }
6928 }
6929 FocusWindow(NULL);
6930}
6931
6932// Important: this alone doesn't alter current ImDrawList state. This is called by PushFont/PopFont only.
6934{
6935 ImGuiContext& g = *GImGui;
6936 IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ?
6937 IM_ASSERT(font->Scale > 0.0f);
6938 g.Font = font;
6939 g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale);
6941
6942 ImFontAtlas* atlas = g.Font->ContainerAtlas;
6947}
6948
6950{
6951 ImGuiContext& g = *GImGui;
6952 if (!font)
6953 font = GetDefaultFont();
6954 SetCurrentFont(font);
6955 g.FontStack.push_back(font);
6957}
6958
6966
6967void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled)
6968{
6969 ImGuiContext& g = *GImGui;
6970 ImGuiItemFlags item_flags = g.CurrentItemFlags;
6971 IM_ASSERT(item_flags == g.ItemFlagsStack.back());
6972 if (enabled)
6973 item_flags |= option;
6974 else
6975 item_flags &= ~option;
6976 g.CurrentItemFlags = item_flags;
6977 g.ItemFlagsStack.push_back(item_flags);
6978}
6979
6981{
6982 ImGuiContext& g = *GImGui;
6983 IM_ASSERT(g.ItemFlagsStack.Size > 1); // Too many calls to PopItemFlag() - we always leave a 0 at the bottom of the stack.
6986}
6987
6988// BeginDisabled()/EndDisabled()
6989// - Those can be nested but it cannot be used to enable an already disabled section (a single BeginDisabled(true) in the stack is enough to keep everything disabled)
6990// - Visually this is currently altering alpha, but it is expected that in a future styling system this would work differently.
6991// - Feedback welcome at https://github.com/ocornut/imgui/issues/211
6992// - BeginDisabled(false) essentially does nothing useful but is provided to facilitate use of boolean expressions. If you can avoid calling BeginDisabled(False)/EndDisabled() best to avoid it.
6993// - Optimized shortcuts instead of PushStyleVar() + PushItemFlag()
6994void ImGui::BeginDisabled(bool disabled)
6995{
6996 ImGuiContext& g = *GImGui;
6997 bool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0;
6998 if (!was_disabled && disabled)
6999 {
7001 g.Style.Alpha *= g.Style.DisabledAlpha; // PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * g.Style.DisabledAlpha);
7002 }
7003 if (was_disabled || disabled)
7007}
7008
7010{
7011 ImGuiContext& g = *GImGui;
7014 bool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0;
7015 //PopItemFlag();
7018 if (was_disabled && (g.CurrentItemFlags & ImGuiItemFlags_Disabled) == 0)
7019 g.Style.Alpha = g.DisabledAlphaBackup; //PopStyleVar();
7020}
7021
7022void ImGui::PushTabStop(bool tab_stop)
7023{
7025}
7026
7028{
7029 PopItemFlag();
7030}
7031
7033{
7035}
7036
7038{
7039 PopItemFlag();
7040}
7041
7042void ImGui::PushTextWrapPos(float wrap_pos_x)
7043{
7044 ImGuiWindow* window = GetCurrentWindow();
7045 window->DC.TextWrapPosStack.push_back(window->DC.TextWrapPos);
7046 window->DC.TextWrapPos = wrap_pos_x;
7047}
7048
7050{
7051 ImGuiWindow* window = GetCurrentWindow();
7052 window->DC.TextWrapPos = window->DC.TextWrapPosStack.back();
7053 window->DC.TextWrapPosStack.pop_back();
7054}
7055
7056static ImGuiWindow* GetCombinedRootWindow(ImGuiWindow* window, bool popup_hierarchy)
7057{
7058 ImGuiWindow* last_window = NULL;
7059 while (last_window != window)
7060 {
7061 last_window = window;
7062 window = window->RootWindow;
7063 if (popup_hierarchy)
7064 window = window->RootWindowPopupTree;
7065 }
7066 return window;
7067}
7068
7069bool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent, bool popup_hierarchy)
7070{
7071 ImGuiWindow* window_root = GetCombinedRootWindow(window, popup_hierarchy);
7072 if (window_root == potential_parent)
7073 return true;
7074 while (window != NULL)
7075 {
7076 if (window == potential_parent)
7077 return true;
7078 if (window == window_root) // end of chain
7079 return false;
7080 window = window->ParentWindow;
7081 }
7082 return false;
7083}
7084
7086{
7087 if (window->RootWindow == potential_parent)
7088 return true;
7089 while (window != NULL)
7090 {
7091 if (window == potential_parent)
7092 return true;
7093 window = window->ParentWindowInBeginStack;
7094 }
7095 return false;
7096}
7097
7098bool ImGui::IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_below)
7099{
7100 ImGuiContext& g = *GImGui;
7101
7102 // It would be saner to ensure that display layer is always reflected in the g.Windows[] order, which would likely requires altering all manipulations of that array
7103 const int display_layer_delta = GetWindowDisplayLayer(potential_above) - GetWindowDisplayLayer(potential_below);
7104 if (display_layer_delta != 0)
7105 return display_layer_delta > 0;
7106
7107 for (int i = g.Windows.Size - 1; i >= 0; i--)
7108 {
7109 ImGuiWindow* candidate_window = g.Windows[i];
7110 if (candidate_window == potential_above)
7111 return true;
7112 if (candidate_window == potential_below)
7113 return false;
7114 }
7115 return false;
7116}
7117
7119{
7120 IM_ASSERT((flags & (ImGuiHoveredFlags_AllowWhenOverlapped | ImGuiHoveredFlags_AllowWhenDisabled)) == 0); // Flags not supported by this function
7121 ImGuiContext& g = *GImGui;
7122 ImGuiWindow* ref_window = g.HoveredWindow;
7123 ImGuiWindow* cur_window = g.CurrentWindow;
7124 if (ref_window == NULL)
7125 return false;
7126
7127 if ((flags & ImGuiHoveredFlags_AnyWindow) == 0)
7128 {
7129 IM_ASSERT(cur_window); // Not inside a Begin()/End()
7130 const bool popup_hierarchy = (flags & ImGuiHoveredFlags_NoPopupHierarchy) == 0;
7131 if (flags & ImGuiHoveredFlags_RootWindow)
7132 cur_window = GetCombinedRootWindow(cur_window, popup_hierarchy);
7133
7134 bool result;
7136 result = IsWindowChildOf(ref_window, cur_window, popup_hierarchy);
7137 else
7138 result = (ref_window == cur_window);
7139 if (!result)
7140 return false;
7141 }
7142
7143 if (!IsWindowContentHoverable(ref_window, flags))
7144 return false;
7146 if (g.ActiveId != 0 && !g.ActiveIdAllowOverlap && g.ActiveId != ref_window->MoveId)
7147 return false;
7148 return true;
7149}
7150
7152{
7153 ImGuiContext& g = *GImGui;
7154 ImGuiWindow* ref_window = g.NavWindow;
7155 ImGuiWindow* cur_window = g.CurrentWindow;
7156
7157 if (ref_window == NULL)
7158 return false;
7159 if (flags & ImGuiFocusedFlags_AnyWindow)
7160 return true;
7161
7162 IM_ASSERT(cur_window); // Not inside a Begin()/End()
7163 const bool popup_hierarchy = (flags & ImGuiFocusedFlags_NoPopupHierarchy) == 0;
7164 if (flags & ImGuiHoveredFlags_RootWindow)
7165 cur_window = GetCombinedRootWindow(cur_window, popup_hierarchy);
7166
7168 return IsWindowChildOf(ref_window, cur_window, popup_hierarchy);
7169 else
7170 return (ref_window == cur_window);
7171}
7172
7173// Can we focus this window with CTRL+TAB (or PadMenu + PadFocusPrev/PadFocusNext)
7174// Note that NoNavFocus makes the window not reachable with CTRL+TAB but it can still be focused with mouse or programmatically.
7175// If you want a window to never be focused, you may use the e.g. NoInputs flag.
7177{
7178 return window->WasActive && window == window->RootWindow && !(window->Flags & ImGuiWindowFlags_NoNavFocus);
7179}
7180
7182{
7183 ImGuiWindow* window = GImGui->CurrentWindow;
7184 return window->Size.x;
7185}
7186
7188{
7189 ImGuiWindow* window = GImGui->CurrentWindow;
7190 return window->Size.y;
7191}
7192
7194{
7195 ImGuiContext& g = *GImGui;
7196 ImGuiWindow* window = g.CurrentWindow;
7197 return window->Pos;
7198}
7199
7200void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond)
7201{
7202 // Test condition (NB: bit 0 is always true) and clear flags for next time
7203 if (cond && (window->SetWindowPosAllowFlags & cond) == 0)
7204 return;
7205
7206 IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
7208 window->SetWindowPosVal = ImVec2(FLT_MAX, FLT_MAX);
7209
7210 // Set
7211 const ImVec2 old_pos = window->Pos;
7212 window->Pos = ImFloor(pos);
7213 ImVec2 offset = window->Pos - old_pos;
7214 if (offset.x == 0.0f && offset.y == 0.0f)
7215 return;
7216 MarkIniSettingsDirty(window);
7217 window->DC.CursorPos += offset; // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor
7218 window->DC.CursorMaxPos += offset; // And more importantly we need to offset CursorMaxPos/CursorStartPos this so ContentSize calculation doesn't get affected.
7219 window->DC.IdealMaxPos += offset;
7220 window->DC.CursorStartPos += offset;
7221}
7222
7224{
7226 SetWindowPos(window, pos, cond);
7227}
7228
7229void ImGui::SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond)
7230{
7231 if (ImGuiWindow* window = FindWindowByName(name))
7232 SetWindowPos(window, pos, cond);
7233}
7234
7236{
7238 return window->Size;
7239}
7240
7241void ImGui::SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond)
7242{
7243 // Test condition (NB: bit 0 is always true) and clear flags for next time
7244 if (cond && (window->SetWindowSizeAllowFlags & cond) == 0)
7245 return;
7246
7247 IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
7249
7250 // Set
7251 ImVec2 old_size = window->SizeFull;
7252 window->AutoFitFramesX = (size.x <= 0.0f) ? 2 : 0;
7253 window->AutoFitFramesY = (size.y <= 0.0f) ? 2 : 0;
7254 if (size.x <= 0.0f)
7255 window->AutoFitOnlyGrows = false;
7256 else
7257 window->SizeFull.x = IM_FLOOR(size.x);
7258 if (size.y <= 0.0f)
7259 window->AutoFitOnlyGrows = false;
7260 else
7261 window->SizeFull.y = IM_FLOOR(size.y);
7262 if (old_size.x != window->SizeFull.x || old_size.y != window->SizeFull.y)
7263 MarkIniSettingsDirty(window);
7264}
7265
7267{
7268 SetWindowSize(GImGui->CurrentWindow, size, cond);
7269}
7270
7271void ImGui::SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond)
7272{
7273 if (ImGuiWindow* window = FindWindowByName(name))
7274 SetWindowSize(window, size, cond);
7275}
7276
7277void ImGui::SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond)
7278{
7279 // Test condition (NB: bit 0 is always true) and clear flags for next time
7280 if (cond && (window->SetWindowCollapsedAllowFlags & cond) == 0)
7281 return;
7283
7284 // Set
7285 window->Collapsed = collapsed;
7286}
7287
7288void ImGui::SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size)
7289{
7290 IM_ASSERT(window->HitTestHoleSize.x == 0); // We don't support multiple holes/hit test filters
7291 window->HitTestHoleSize = ImVec2ih(size);
7292 window->HitTestHoleOffset = ImVec2ih(pos - window->Pos);
7293}
7294
7296{
7297 window->Hidden = window->SkipItems = true;
7298 window->HiddenFramesCanSkipItems = 1;
7299}
7300
7301void ImGui::SetWindowCollapsed(bool collapsed, ImGuiCond cond)
7302{
7303 SetWindowCollapsed(GImGui->CurrentWindow, collapsed, cond);
7304}
7305
7307{
7309 return window->Collapsed;
7310}
7311
7313{
7315 return window->Appearing;
7316}
7317
7318void ImGui::SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond)
7319{
7320 if (ImGuiWindow* window = FindWindowByName(name))
7321 SetWindowCollapsed(window, collapsed, cond);
7322}
7323
7328
7329void ImGui::SetWindowFocus(const char* name)
7330{
7331 if (name)
7332 {
7333 if (ImGuiWindow* window = FindWindowByName(name))
7334 FocusWindow(window);
7335 }
7336 else
7337 {
7338 FocusWindow(NULL);
7339 }
7340}
7341
7342void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pivot)
7343{
7344 ImGuiContext& g = *GImGui;
7345 IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
7347 g.NextWindowData.PosVal = pos;
7348 g.NextWindowData.PosPivotVal = pivot;
7349 g.NextWindowData.PosCond = cond ? cond : ImGuiCond_Always;
7350}
7351
7353{
7354 ImGuiContext& g = *GImGui;
7355 IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
7357 g.NextWindowData.SizeVal = size;
7358 g.NextWindowData.SizeCond = cond ? cond : ImGuiCond_Always;
7359}
7360
7361void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback, void* custom_callback_user_data)
7362{
7363 ImGuiContext& g = *GImGui;
7365 g.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max);
7366 g.NextWindowData.SizeCallback = custom_callback;
7367 g.NextWindowData.SizeCallbackUserData = custom_callback_user_data;
7368}
7369
7370// Content size = inner scrollable rectangle, padded with WindowPadding.
7371// SetNextWindowContentSize(ImVec2(100,100) + ImGuiWindowFlags_AlwaysAutoResize will always allow submitting a 100x100 item.
7378
7385
7387{
7388 ImGuiContext& g = *GImGui;
7389 IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
7391 g.NextWindowData.CollapsedVal = collapsed;
7393}
7394
7400
7407
7409{
7410 ImGuiWindow* window = GetCurrentWindow();
7411 return window->DrawList;
7412}
7413
7415{
7416 return GImGui->Font;
7417}
7418
7420{
7421 return GImGui->FontSize;
7422}
7423
7428
7430{
7431 IM_ASSERT(scale > 0.0f);
7432 ImGuiContext& g = *GImGui;
7433 ImGuiWindow* window = GetCurrentWindow();
7434 window->FontWindowScale = scale;
7436}
7437
7444
7446{
7447 ImGuiContext& g = *GImGui;
7449 g.CurrentFocusScopeId = id;
7450}
7451
7453{
7454 ImGuiContext& g = *GImGui;
7455 IM_ASSERT(g.FocusScopeStack.Size > 0); // Too many PopFocusScope() ?
7458}
7459
7460// Note: this will likely be called ActivateItem() once we rework our Focus/Activation system!
7462{
7463 ImGuiContext& g = *GImGui;
7464 ImGuiWindow* window = g.CurrentWindow;
7465 IM_ASSERT(offset >= -1); // -1 is allowed but not below
7466 IMGUI_DEBUG_LOG_ACTIVEID("SetKeyboardFocusHere(%d) in window \"%s\"\n", offset, window->Name);
7467
7468 // It makes sense in the vast majority of cases to never interrupt a drag and drop.
7469 // When we refactor this function into ActivateItem() we may want to make this an option.
7470 // MovingWindow is protected from most user inputs using SetActiveIdUsingNavAndKeys(), but
7471 // is also automatically dropped in the event g.ActiveId is stolen.
7472 if (g.DragDropActive || g.MovingWindow != NULL)
7473 {
7474 IMGUI_DEBUG_LOG_ACTIVEID("SetKeyboardFocusHere() ignored while DragDropActive!\n");
7475 return;
7476 }
7477
7478 SetNavWindow(window);
7479
7481 NavMoveRequestSubmit(ImGuiDir_None, offset < 0 ? ImGuiDir_Up : ImGuiDir_Down, ImGuiNavMoveFlags_Tabbing | ImGuiNavMoveFlags_FocusApi, scroll_flags); // FIXME-NAV: Once we refactor tabbing, add LegacyApi flag to not activate non-inputable.
7482 if (offset == -1)
7483 {
7485 }
7486 else
7487 {
7488 g.NavTabbingDir = 1;
7489 g.NavTabbingCounter = offset + 1;
7490 }
7491}
7492
7494{
7495 ImGuiContext& g = *GImGui;
7496 ImGuiWindow* window = g.CurrentWindow;
7497 if (!window->Appearing)
7498 return;
7499 if (g.NavWindow != window->RootWindowForNav || (!g.NavInitRequest && g.NavInitResultId == 0) || g.NavLayer != window->DC.NavLayerCurrent)
7500 return;
7501
7502 g.NavInitRequest = false;
7505 NavUpdateAnyRequestFlag();
7506
7507 // Scroll could be done in NavInitRequestApplyResult() via an opt-in flag (we however don't want regular init requests to scroll)
7508 if (!window->ClipRect.Contains(g.LastItemData.Rect))
7510}
7511
7513{
7514 ImGuiWindow* window = GImGui->CurrentWindow;
7515 window->DC.StateStorage = tree ? tree : &window->StateStorage;
7516}
7517
7519{
7520 ImGuiWindow* window = GImGui->CurrentWindow;
7521 return window->DC.StateStorage;
7522}
7523
7524void ImGui::PushID(const char* str_id)
7525{
7526 ImGuiContext& g = *GImGui;
7527 ImGuiWindow* window = g.CurrentWindow;
7528 ImGuiID id = window->GetID(str_id);
7529 window->IDStack.push_back(id);
7530}
7531
7532void ImGui::PushID(const char* str_id_begin, const char* str_id_end)
7533{
7534 ImGuiContext& g = *GImGui;
7535 ImGuiWindow* window = g.CurrentWindow;
7536 ImGuiID id = window->GetID(str_id_begin, str_id_end);
7537 window->IDStack.push_back(id);
7538}
7539
7540void ImGui::PushID(const void* ptr_id)
7541{
7542 ImGuiContext& g = *GImGui;
7543 ImGuiWindow* window = g.CurrentWindow;
7544 ImGuiID id = window->GetID(ptr_id);
7545 window->IDStack.push_back(id);
7546}
7547
7548void ImGui::PushID(int int_id)
7549{
7550 ImGuiContext& g = *GImGui;
7551 ImGuiWindow* window = g.CurrentWindow;
7552 ImGuiID id = window->GetID(int_id);
7553 window->IDStack.push_back(id);
7554}
7555
7556// Push a given id value ignoring the ID stack as a seed.
7558{
7559 ImGuiContext& g = *GImGui;
7560 ImGuiWindow* window = g.CurrentWindow;
7561 if (g.DebugHookIdInfo == id)
7562 DebugHookIdInfo(id, ImGuiDataType_ID, NULL, NULL);
7563 window->IDStack.push_back(id);
7564}
7565
7566// Helper to avoid a common series of PushOverrideID -> GetID() -> PopID() call
7567// (note that when using this pattern, TestEngine's "Stack Tool" will tend to not display the intermediate stack level.
7568// for that to work we would need to do PushOverrideID() -> ItemAdd() -> PopID() which would alter widget code a little more)
7569ImGuiID ImGui::GetIDWithSeed(const char* str, const char* str_end, ImGuiID seed)
7570{
7571 ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
7572 ImGuiContext& g = *GImGui;
7573 if (g.DebugHookIdInfo == id)
7574 DebugHookIdInfo(id, ImGuiDataType_String, str, str_end);
7575 return id;
7576}
7577
7579{
7580 ImGuiID id = ImHashData(&n, sizeof(n), seed);
7581 ImGuiContext& g = *GImGui;
7582 if (g.DebugHookIdInfo == id)
7583 DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL);
7584 return id;
7585}
7586
7588{
7589 ImGuiWindow* window = GImGui->CurrentWindow;
7590 IM_ASSERT(window->IDStack.Size > 1); // Too many PopID(), or could be popping in a wrong/different window?
7591 window->IDStack.pop_back();
7592}
7593
7594ImGuiID ImGui::GetID(const char* str_id)
7595{
7596 ImGuiWindow* window = GImGui->CurrentWindow;
7597 return window->GetID(str_id);
7598}
7599
7600ImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end)
7601{
7602 ImGuiWindow* window = GImGui->CurrentWindow;
7603 return window->GetID(str_id_begin, str_id_end);
7604}
7605
7606ImGuiID ImGui::GetID(const void* ptr_id)
7607{
7608 ImGuiWindow* window = GImGui->CurrentWindow;
7609 return window->GetID(ptr_id);
7610}
7611
7613{
7614 ImGuiWindow* window = GImGui->CurrentWindow;
7615 return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size));
7616}
7617
7618bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
7619{
7620 ImGuiWindow* window = GImGui->CurrentWindow;
7621 return window->ClipRect.Overlaps(ImRect(rect_min, rect_max));
7622}
7623
7624
7625//-----------------------------------------------------------------------------
7626// [SECTION] INPUTS
7627//-----------------------------------------------------------------------------
7628// - GetKeyData() [Internal]
7629// - GetKeyIndex() [Internal]
7630// - GetKeyName()
7631// - GetKeyChordName() [Internal]
7632// - CalcTypematicRepeatAmount() [Internal]
7633// - GetTypematicRepeatRate() [Internal]
7634// - GetKeyPressedAmount() [Internal]
7635// - GetKeyMagnitude2d() [Internal]
7636//-----------------------------------------------------------------------------
7637// - UpdateKeyRoutingTable() [Internal]
7638// - GetRoutingIdFromOwnerId() [Internal]
7639// - GetShortcutRoutingData() [Internal]
7640// - CalcRoutingScore() [Internal]
7641// - SetShortcutRouting() [Internal]
7642// - TestShortcutRouting() [Internal]
7643//-----------------------------------------------------------------------------
7644// - IsKeyDown()
7645// - IsKeyPressed()
7646// - IsKeyReleased()
7647//-----------------------------------------------------------------------------
7648// - IsMouseDown()
7649// - IsMouseClicked()
7650// - IsMouseReleased()
7651// - IsMouseDoubleClicked()
7652// - GetMouseClickedCount()
7653// - IsMouseHoveringRect() [Internal]
7654// - IsMouseDragPastThreshold() [Internal]
7655// - IsMouseDragging()
7656// - GetMousePos()
7657// - GetMousePosOnOpeningCurrentPopup()
7658// - IsMousePosValid()
7659// - IsAnyMouseDown()
7660// - GetMouseDragDelta()
7661// - ResetMouseDragDelta()
7662// - GetMouseCursor()
7663// - SetMouseCursor()
7664//-----------------------------------------------------------------------------
7665// - UpdateAliasKey()
7666// - GetMergedModsFromKeys()
7667// - UpdateKeyboardInputs()
7668// - UpdateMouseInputs()
7669//-----------------------------------------------------------------------------
7670// - LockWheelingWindow [Internal]
7671// - FindBestWheelingWindow [Internal]
7672// - UpdateMouseWheel() [Internal]
7673//-----------------------------------------------------------------------------
7674// - SetNextFrameWantCaptureKeyboard()
7675// - SetNextFrameWantCaptureMouse()
7676//-----------------------------------------------------------------------------
7677// - GetInputSourceName() [Internal]
7678// - DebugPrintInputEvent() [Internal]
7679// - UpdateInputEvents() [Internal]
7680//-----------------------------------------------------------------------------
7681// - GetKeyOwner() [Internal]
7682// - TestKeyOwner() [Internal]
7683// - SetKeyOwner() [Internal]
7684// - SetItemKeyOwner() [Internal]
7685// - Shortcut() [Internal]
7686//-----------------------------------------------------------------------------
7687
7689{
7690 ImGuiContext& g = *GImGui;
7691
7692 // Special storage location for mods
7693 if (key & ImGuiMod_Mask_)
7694 key = ConvertSingleModFlagToKey(key);
7695
7696#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
7698 if (IsLegacyKey(key) && g.IO.KeyMap[key] != -1)
7699 key = (ImGuiKey)g.IO.KeyMap[key]; // Remap native->imgui or imgui->native
7700#else
7701 IM_ASSERT(IsNamedKey(key) && "Support for user key indices was dropped in favor of ImGuiKey. Please update backend & user code.");
7702#endif
7703 return &g.IO.KeysData[key - ImGuiKey_KeysData_OFFSET];
7704}
7705
7706#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
7708{
7709 ImGuiContext& g = *GImGui;
7710 IM_ASSERT(IsNamedKey(key));
7711 const ImGuiKeyData* key_data = GetKeyData(key);
7712 return (ImGuiKey)(key_data - g.IO.KeysData);
7713}
7714#endif
7715
7716// Those names a provided for debugging purpose and are not meant to be saved persistently not compared.
7717static const char* const GKeyNames[] =
7718{
7719 "Tab", "LeftArrow", "RightArrow", "UpArrow", "DownArrow", "PageUp", "PageDown",
7720 "Home", "End", "Insert", "Delete", "Backspace", "Space", "Enter", "Escape",
7721 "LeftCtrl", "LeftShift", "LeftAlt", "LeftSuper", "RightCtrl", "RightShift", "RightAlt", "RightSuper", "Menu",
7722 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H",
7723 "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
7724 "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
7725 "Apostrophe", "Comma", "Minus", "Period", "Slash", "Semicolon", "Equal", "LeftBracket",
7726 "Backslash", "RightBracket", "GraveAccent", "CapsLock", "ScrollLock", "NumLock", "PrintScreen",
7727 "Pause", "Keypad0", "Keypad1", "Keypad2", "Keypad3", "Keypad4", "Keypad5", "Keypad6",
7728 "Keypad7", "Keypad8", "Keypad9", "KeypadDecimal", "KeypadDivide", "KeypadMultiply",
7729 "KeypadSubtract", "KeypadAdd", "KeypadEnter", "KeypadEqual",
7730 "GamepadStart", "GamepadBack",
7731 "GamepadFaceLeft", "GamepadFaceRight", "GamepadFaceUp", "GamepadFaceDown",
7732 "GamepadDpadLeft", "GamepadDpadRight", "GamepadDpadUp", "GamepadDpadDown",
7733 "GamepadL1", "GamepadR1", "GamepadL2", "GamepadR2", "GamepadL3", "GamepadR3",
7734 "GamepadLStickLeft", "GamepadLStickRight", "GamepadLStickUp", "GamepadLStickDown",
7735 "GamepadRStickLeft", "GamepadRStickRight", "GamepadRStickUp", "GamepadRStickDown",
7736 "MouseLeft", "MouseRight", "MouseMiddle", "MouseX1", "MouseX2", "MouseWheelX", "MouseWheelY",
7737 "ModCtrl", "ModShift", "ModAlt", "ModSuper", // ReservedForModXXX are showing the ModXXX names.
7738};
7740
7742{
7743#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO
7744 IM_ASSERT((IsNamedKey(key) || key == ImGuiKey_None) && "Support for user key indices was dropped in favor of ImGuiKey. Please update backend and user code.");
7745#else
7746 if (IsLegacyKey(key))
7747 {
7748 ImGuiIO& io = GetIO();
7749 if (io.KeyMap[key] == -1)
7750 return "N/A";
7752 key = (ImGuiKey)io.KeyMap[key];
7753 }
7754#endif
7755 if (key == ImGuiKey_None)
7756 return "None";
7757 if (key & ImGuiMod_Mask_)
7758 key = ConvertSingleModFlagToKey(key);
7759 if (!IsNamedKey(key))
7760 return "Unknown";
7761
7762 return GKeyNames[key - ImGuiKey_NamedKey_BEGIN];
7763}
7764
7765// ImGuiMod_Shortcut is translated to either Ctrl or Super.
7766void ImGui::GetKeyChordName(ImGuiKeyChord key_chord, char* out_buf, int out_buf_size)
7767{
7768 ImGuiContext& g = *GImGui;
7769 if (key_chord & ImGuiMod_Shortcut)
7770 key_chord = ConvertShortcutMod(key_chord);
7771 ImFormatString(out_buf, (size_t)out_buf_size, "%s%s%s%s%s",
7772 (key_chord & ImGuiMod_Ctrl) ? "Ctrl+" : "",
7773 (key_chord & ImGuiMod_Shift) ? "Shift+" : "",
7774 (key_chord & ImGuiMod_Alt) ? "Alt+" : "",
7775 (key_chord & ImGuiMod_Super) ? (g.IO.ConfigMacOSXBehaviors ? "Cmd+" : "Super+") : "",
7776 GetKeyName((ImGuiKey)(key_chord & ~ImGuiMod_Mask_)));
7777}
7778
7779// t0 = previous time (e.g.: g.Time - g.IO.DeltaTime)
7780// t1 = current time (e.g.: g.Time)
7781// An event is triggered at:
7782// t = 0.0f t = repeat_delay, t = repeat_delay + repeat_rate*N
7783int ImGui::CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate)
7784{
7785 if (t1 == 0.0f)
7786 return 1;
7787 if (t0 >= t1)
7788 return 0;
7789 if (repeat_rate <= 0.0f)
7790 return (t0 < repeat_delay) && (t1 >= repeat_delay);
7791 const int count_t0 = (t0 < repeat_delay) ? -1 : (int)((t0 - repeat_delay) / repeat_rate);
7792 const int count_t1 = (t1 < repeat_delay) ? -1 : (int)((t1 - repeat_delay) / repeat_rate);
7793 const int count = count_t1 - count_t0;
7794 return count;
7795}
7796
7797void ImGui::GetTypematicRepeatRate(ImGuiInputFlags flags, float* repeat_delay, float* repeat_rate)
7798{
7799 ImGuiContext& g = *GImGui;
7800 switch (flags & ImGuiInputFlags_RepeatRateMask_)
7801 {
7802 case ImGuiInputFlags_RepeatRateNavMove: *repeat_delay = g.IO.KeyRepeatDelay * 0.72f; *repeat_rate = g.IO.KeyRepeatRate * 0.80f; return;
7803 case ImGuiInputFlags_RepeatRateNavTweak: *repeat_delay = g.IO.KeyRepeatDelay * 0.72f; *repeat_rate = g.IO.KeyRepeatRate * 0.30f; return;
7804 case ImGuiInputFlags_RepeatRateDefault: default: *repeat_delay = g.IO.KeyRepeatDelay * 1.00f; *repeat_rate = g.IO.KeyRepeatRate * 1.00f; return;
7805 }
7806}
7807
7808// Return value representing the number of presses in the last time period, for the given repeat rate
7809// (most often returns 0 or 1. The result is generally only >1 when RepeatRate is smaller than DeltaTime, aka large DeltaTime or fast RepeatRate)
7810int ImGui::GetKeyPressedAmount(ImGuiKey key, float repeat_delay, float repeat_rate)
7811{
7812 ImGuiContext& g = *GImGui;
7813 const ImGuiKeyData* key_data = GetKeyData(key);
7814 if (!key_data->Down) // In theory this should already be encoded as (DownDuration < 0.0f), but testing this facilitates eating mechanism (until we finish work on key ownership)
7815 return 0;
7816 const float t = key_data->DownDuration;
7817 return CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, repeat_delay, repeat_rate);
7818}
7819
7820// Return 2D vector representing the combination of four cardinal direction, with analog value support (for e.g. ImGuiKey_GamepadLStick* values).
7822{
7823 return ImVec2(
7824 GetKeyData(key_right)->AnalogValue - GetKeyData(key_left)->AnalogValue,
7825 GetKeyData(key_down)->AnalogValue - GetKeyData(key_up)->AnalogValue);
7826}
7827
7828// Rewrite routing data buffers to strip old entries + sort by key to make queries not touch scattered data.
7829// Entries D,A,B,B,A,C,B --> A,A,B,B,B,C,D
7830// Index A:1 B:2 C:5 D:0 --> A:0 B:2 C:5 D:6
7831// See 'Metrics->Key Owners & Shortcut Routing' to visualize the result of that operation.
7832static void ImGui::UpdateKeyRoutingTable(ImGuiKeyRoutingTable* rt)
7833{
7834 ImGuiContext& g = *GImGui;
7835 rt->EntriesNext.resize(0);
7836 for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1))
7837 {
7838 const int new_routing_start_idx = rt->EntriesNext.Size;
7839 ImGuiKeyRoutingData* routing_entry;
7840 for (int old_routing_idx = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; old_routing_idx != -1; old_routing_idx = routing_entry->NextEntryIndex)
7841 {
7842 routing_entry = &rt->Entries[old_routing_idx];
7843 routing_entry->RoutingCurr = routing_entry->RoutingNext; // Update entry
7844 routing_entry->RoutingNext = ImGuiKeyOwner_None;
7845 routing_entry->RoutingNextScore = 255;
7846 if (routing_entry->RoutingCurr == ImGuiKeyOwner_None)
7847 continue;
7848 rt->EntriesNext.push_back(*routing_entry); // Write alive ones into new buffer
7849
7850 // Apply routing to owner if there's no owner already (RoutingCurr == None at this point)
7851 if (routing_entry->Mods == g.IO.KeyMods)
7852 {
7853 ImGuiKeyOwnerData* owner_data = ImGui::GetKeyOwnerData(key);
7854 if (owner_data->OwnerCurr == ImGuiKeyOwner_None)
7855 owner_data->OwnerCurr = routing_entry->RoutingCurr;
7856 }
7857 }
7858
7859 // Rewrite linked-list
7860 rt->Index[key - ImGuiKey_NamedKey_BEGIN] = (ImGuiKeyRoutingIndex)(new_routing_start_idx < rt->EntriesNext.Size ? new_routing_start_idx : -1);
7861 for (int n = new_routing_start_idx; n < rt->EntriesNext.Size; n++)
7862 rt->EntriesNext[n].NextEntryIndex = (ImGuiKeyRoutingIndex)((n + 1 < rt->EntriesNext.Size) ? n + 1 : -1);
7863 }
7864 rt->Entries.swap(rt->EntriesNext); // Swap new and old indexes
7865}
7866
7867// owner_id may be None/Any, but routing_id needs to be always be set, so we default to GetCurrentFocusScope().
7868static inline ImGuiID GetRoutingIdFromOwnerId(ImGuiID owner_id)
7869{
7870 ImGuiContext& g = *GImGui;
7871 return (owner_id != ImGuiKeyOwner_None && owner_id != ImGuiKeyOwner_Any) ? owner_id : g.CurrentFocusScopeId;
7872}
7873
7875{
7876 // Majority of shortcuts will be Key + any number of Mods
7877 // We accept _Single_ mod with ImGuiKey_None.
7878 // - Shortcut(ImGuiKey_S | ImGuiMod_Ctrl); // Legal
7879 // - Shortcut(ImGuiKey_S | ImGuiMod_Ctrl | ImGuiMod_Shift); // Legal
7880 // - Shortcut(ImGuiMod_Ctrl); // Legal
7881 // - Shortcut(ImGuiMod_Ctrl | ImGuiMod_Shift); // Not legal
7882 ImGuiContext& g = *GImGui;
7884 ImGuiKeyRoutingData* routing_data;
7885 if (key_chord & ImGuiMod_Shortcut)
7886 key_chord = ConvertShortcutMod(key_chord);
7887 ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_);
7888 ImGuiKey mods = (ImGuiKey)(key_chord & ImGuiMod_Mask_);
7889 if (key == ImGuiKey_None)
7890 key = ConvertSingleModFlagToKey(mods);
7891 IM_ASSERT(IsNamedKey(key));
7892
7893 // Get (in the majority of case, the linked list will have one element so this should be 2 reads.
7894 // Subsequent elements will be contiguous in memory as list is sorted/rebuilt in NewFrame).
7895 for (ImGuiKeyRoutingIndex idx = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; idx != -1; idx = routing_data->NextEntryIndex)
7896 {
7897 routing_data = &rt->Entries[idx];
7898 if (routing_data->Mods == mods)
7899 return routing_data;
7900 }
7901
7902 // Add to linked-list
7903 ImGuiKeyRoutingIndex routing_data_idx = (ImGuiKeyRoutingIndex)rt->Entries.Size;
7905 routing_data = &rt->Entries[routing_data_idx];
7906 routing_data->Mods = (ImU16)mods;
7907 routing_data->NextEntryIndex = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; // Setup linked list
7908 rt->Index[key - ImGuiKey_NamedKey_BEGIN] = routing_data_idx;
7909 return routing_data;
7910}
7911
7912// Current score encoding (lower is highest priority):
7913// - 0: ImGuiInputFlags_RouteGlobalHigh
7914// - 1: ImGuiInputFlags_RouteFocused (if item active)
7915// - 2: ImGuiInputFlags_RouteGlobal
7916// - 3+: ImGuiInputFlags_RouteFocused (if window in focus-stack)
7917// - 254: ImGuiInputFlags_RouteGlobalLow
7918// - 255: never route
7919// 'flags' should include an explicit routing policy
7920static int CalcRoutingScore(ImGuiWindow* location, ImGuiID owner_id, ImGuiInputFlags flags)
7921{
7922 if (flags & ImGuiInputFlags_RouteFocused)
7923 {
7924 ImGuiContext& g = *GImGui;
7925 ImGuiWindow* focused = g.NavWindow;
7926
7927 // ActiveID gets top priority
7928 // (we don't check g.ActiveIdUsingAllKeys here. Routing is applied but if input ownership is tested later it may discard it)
7929 if (owner_id != 0 && g.ActiveId == owner_id)
7930 return 1;
7931
7932 // Score based on distance to focused window (lower is better)
7933 // Assuming both windows are submitting a routing request,
7934 // - When Window....... is focused -> Window scores 3 (best), Window/ChildB scores 255 (no match)
7935 // - When Window/ChildB is focused -> Window scores 4, Window/ChildB scores 3 (best)
7936 // Assuming only WindowA is submitting a routing request,
7937 // - When Window/ChildB is focused -> Window scores 4 (best), Window/ChildB doesn't have a score.
7938 if (focused != NULL && focused->RootWindow == location->RootWindow)
7939 for (int next_score = 3; focused != NULL; next_score++)
7940 {
7941 if (focused == location)
7942 {
7943 IM_ASSERT(next_score < 255);
7944 return next_score;
7945 }
7946 focused = (focused->RootWindow != focused) ? focused->ParentWindow : NULL; // FIXME: This could be later abstracted as a focus path
7947 }
7948 return 255;
7949 }
7950
7951 // ImGuiInputFlags_RouteGlobalHigh is default, so calls without flags are not conditional
7952 if (flags & ImGuiInputFlags_RouteGlobal)
7953 return 2;
7955 return 254;
7956 return 0;
7957}
7958
7959// Request a desired route for an input chord (key + mods).
7960// Return true if the route is available this frame.
7961// - Routes and key ownership are attributed at the beginning of next frame based on best score and mod state.
7962// (Conceptually this does a "Submit for next frame" + "Test for current frame".
7963// As such, it could be called TrySetXXX or SubmitXXX, or the Submit and Test operations should be separate.)
7964// - Using 'owner_id == ImGuiKeyOwner_Any/0': auto-assign an owner based on current focus scope (each window has its focus scope by default)
7965// - Using 'owner_id == ImGuiKeyOwner_None': allows disabling/locking a shortcut.
7967{
7968 ImGuiContext& g = *GImGui;
7969 if ((flags & ImGuiInputFlags_RouteMask_) == 0)
7970 flags |= ImGuiInputFlags_RouteGlobalHigh; // IMPORTANT: This is the default for SetShortcutRouting() but NOT Shortcut()
7971 else
7972 IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiInputFlags_RouteMask_)); // Check that only 1 routing flag is used
7973
7975 if (g.NavWindow == NULL)
7976 return false;
7977 if (flags & ImGuiInputFlags_RouteAlways)
7978 return true;
7979
7980 const int score = CalcRoutingScore(g.CurrentWindow, owner_id, flags);
7981 if (score == 255)
7982 return false;
7983
7984 // Submit routing for NEXT frame (assuming score is sufficient)
7985 // FIXME: Could expose a way to use a "serve last" policy for same score resolution (using <= instead of <).
7986 ImGuiKeyRoutingData* routing_data = GetShortcutRoutingData(key_chord);
7987 const ImGuiID routing_id = GetRoutingIdFromOwnerId(owner_id);
7988 //const bool set_route = (flags & ImGuiInputFlags_ServeLast) ? (score <= routing_data->RoutingNextScore) : (score < routing_data->RoutingNextScore);
7989 if (score < routing_data->RoutingNextScore)
7990 {
7991 routing_data->RoutingNext = routing_id;
7992 routing_data->RoutingNextScore = (ImU8)score;
7993 }
7994
7995 // Return routing state for CURRENT frame
7996 return routing_data->RoutingCurr == routing_id;
7997}
7998
7999// Currently unused by core (but used by tests)
8000// Note: this cannot be turned into GetShortcutRouting() because we do the owner_id->routing_id translation, name would be more misleading.
8002{
8003 const ImGuiID routing_id = GetRoutingIdFromOwnerId(owner_id);
8004 ImGuiKeyRoutingData* routing_data = GetShortcutRoutingData(key_chord); // FIXME: Could avoid creating entry.
8005 return routing_data->RoutingCurr == routing_id;
8006}
8007
8008// Note that Dear ImGui doesn't know the meaning/semantic of ImGuiKey from 0..511: they are legacy native keycodes.
8009// Consider transitioning from 'IsKeyDown(MY_ENGINE_KEY_A)' (<1.87) to IsKeyDown(ImGuiKey_A) (>= 1.87)
8011{
8012 return IsKeyDown(key, ImGuiKeyOwner_Any);
8013}
8014
8016{
8017 const ImGuiKeyData* key_data = GetKeyData(key);
8018 if (!key_data->Down)
8019 return false;
8020 if (!TestKeyOwner(key, owner_id))
8021 return false;
8022 return true;
8023}
8024
8025bool ImGui::IsKeyPressed(ImGuiKey key, bool repeat)
8026{
8028}
8029
8030// Important: unless legacy IsKeyPressed(ImGuiKey, bool repeat=true) which DEFAULT to repeat, this requires EXPLICIT repeat.
8032{
8033 const ImGuiKeyData* key_data = GetKeyData(key);
8034 if (!key_data->Down) // In theory this should already be encoded as (DownDuration < 0.0f), but testing this facilitates eating mechanism (until we finish work on key ownership)
8035 return false;
8036 const float t = key_data->DownDuration;
8037 if (t < 0.0f)
8038 return false;
8039 IM_ASSERT((flags & ~ImGuiInputFlags_SupportedByIsKeyPressed) == 0); // Passing flags not supported by this function!
8040
8041 bool pressed = (t == 0.0f);
8042 if (!pressed && ((flags & ImGuiInputFlags_Repeat) != 0))
8043 {
8044 float repeat_delay, repeat_rate;
8045 GetTypematicRepeatRate(flags, &repeat_delay, &repeat_rate);
8046 pressed = (t > repeat_delay) && GetKeyPressedAmount(key, repeat_delay, repeat_rate) > 0;
8047 }
8048 if (!pressed)
8049 return false;
8050 if (!TestKeyOwner(key, owner_id))
8051 return false;
8052 return true;
8053}
8054
8056{
8057 return IsKeyReleased(key, ImGuiKeyOwner_Any);
8058}
8059
8061{
8062 const ImGuiKeyData* key_data = GetKeyData(key);
8063 if (key_data->DownDurationPrev < 0.0f || key_data->Down)
8064 return false;
8065 if (!TestKeyOwner(key, owner_id))
8066 return false;
8067 return true;
8068}
8069
8071{
8072 ImGuiContext& g = *GImGui;
8073 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
8074 return g.IO.MouseDown[button] && TestKeyOwner(MouseButtonToKey(button), ImGuiKeyOwner_Any); // should be same as IsKeyDown(MouseButtonToKey(button), ImGuiKeyOwner_Any), but this allows legacy code hijacking the io.Mousedown[] array.
8075}
8076
8078{
8079 ImGuiContext& g = *GImGui;
8080 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
8081 return g.IO.MouseDown[button] && TestKeyOwner(MouseButtonToKey(button), owner_id); // Should be same as IsKeyDown(MouseButtonToKey(button), owner_id), but this allows legacy code hijacking the io.Mousedown[] array.
8082}
8083
8085{
8087}
8088
8090{
8091 ImGuiContext& g = *GImGui;
8092 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
8093 if (!g.IO.MouseDown[button]) // In theory this should already be encoded as (DownDuration < 0.0f), but testing this facilitates eating mechanism (until we finish work on key ownership)
8094 return false;
8095 const float t = g.IO.MouseDownDuration[button];
8096 if (t < 0.0f)
8097 return false;
8098 IM_ASSERT((flags & ~ImGuiInputFlags_SupportedByIsKeyPressed) == 0); // Passing flags not supported by this function!
8099
8100 const bool repeat = (flags & ImGuiInputFlags_Repeat) != 0;
8101 const bool pressed = (t == 0.0f) || (repeat && t > g.IO.KeyRepeatDelay && CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0);
8102 if (!pressed)
8103 return false;
8104
8105 if (!TestKeyOwner(MouseButtonToKey(button), owner_id))
8106 return false;
8107
8108 return true;
8109}
8110
8112{
8113 ImGuiContext& g = *GImGui;
8114 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
8115 return g.IO.MouseReleased[button] && TestKeyOwner(MouseButtonToKey(button), ImGuiKeyOwner_Any); // Should be same as IsKeyReleased(MouseButtonToKey(button), ImGuiKeyOwner_Any)
8116}
8117
8119{
8120 ImGuiContext& g = *GImGui;
8121 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
8122 return g.IO.MouseReleased[button] && TestKeyOwner(MouseButtonToKey(button), owner_id); // Should be same as IsKeyReleased(MouseButtonToKey(button), owner_id)
8123}
8124
8126{
8127 ImGuiContext& g = *GImGui;
8128 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
8129 return g.IO.MouseClickedCount[button] == 2 && TestKeyOwner(MouseButtonToKey(button), ImGuiKeyOwner_Any);
8130}
8131
8133{
8134 ImGuiContext& g = *GImGui;
8135 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
8136 return g.IO.MouseClickedCount[button];
8137}
8138
8139// Test if mouse cursor is hovering given rectangle
8140// NB- Rectangle is clipped by our current clip setting
8141// NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding)
8142bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip)
8143{
8144 ImGuiContext& g = *GImGui;
8145
8146 // Clip
8147 ImRect rect_clipped(r_min, r_max);
8148 if (clip)
8149 rect_clipped.ClipWith(g.CurrentWindow->ClipRect);
8150
8151 // Expand for touch input
8152 const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding);
8153 if (!rect_for_touch.Contains(g.IO.MousePos))
8154 return false;
8155 return true;
8156}
8157
8158// Return if a mouse click/drag went past the given threshold. Valid to call during the MouseReleased frame.
8159// [Internal] This doesn't test if the button is pressed
8160bool ImGui::IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold)
8161{
8162 ImGuiContext& g = *GImGui;
8163 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
8164 if (lock_threshold < 0.0f)
8165 lock_threshold = g.IO.MouseDragThreshold;
8166 return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold;
8167}
8168
8169bool ImGui::IsMouseDragging(ImGuiMouseButton button, float lock_threshold)
8170{
8171 ImGuiContext& g = *GImGui;
8172 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
8173 if (!g.IO.MouseDown[button])
8174 return false;
8175 return IsMouseDragPastThreshold(button, lock_threshold);
8176}
8177
8179{
8180 ImGuiContext& g = *GImGui;
8181 return g.IO.MousePos;
8182}
8183
8184// NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed!
8186{
8187 ImGuiContext& g = *GImGui;
8188 if (g.BeginPopupStack.Size > 0)
8189 return g.OpenPopupStack[g.BeginPopupStack.Size - 1].OpenMousePos;
8190 return g.IO.MousePos;
8191}
8192
8193// We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position.
8194bool ImGui::IsMousePosValid(const ImVec2* mouse_pos)
8195{
8196 // The assert is only to silence a false-positive in XCode Static Analysis.
8197 // Because GImGui is not dereferenced in every code path, the static analyzer assume that it may be NULL (which it doesn't for other functions).
8198 IM_ASSERT(GImGui != NULL);
8199 const float MOUSE_INVALID = -256000.0f;
8200 ImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos;
8201 return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID;
8202}
8203
8204// [WILL OBSOLETE] This was designed for backends, but prefer having backend maintain a mask of held mouse buttons, because upcoming input queue system will make this invalid.
8206{
8207 ImGuiContext& g = *GImGui;
8208 for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++)
8209 if (g.IO.MouseDown[n])
8210 return true;
8211 return false;
8212}
8213
8214// Return the delta from the initial clicking position while the mouse button is clicked or was just released.
8215// This is locked and return 0.0f until the mouse moves past a distance threshold at least once.
8216// NB: This is only valid if IsMousePosValid(). backends in theory should always keep mouse position valid when dragging even outside the client window.
8218{
8219 ImGuiContext& g = *GImGui;
8220 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
8221 if (lock_threshold < 0.0f)
8222 lock_threshold = g.IO.MouseDragThreshold;
8223 if (g.IO.MouseDown[button] || g.IO.MouseReleased[button])
8224 if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold)
8226 return g.IO.MousePos - g.IO.MouseClickedPos[button];
8227 return ImVec2(0.0f, 0.0f);
8228}
8229
8231{
8232 ImGuiContext& g = *GImGui;
8233 IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
8234 // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr
8235 g.IO.MouseClickedPos[button] = g.IO.MousePos;
8236}
8237
8238// Get desired mouse cursor shape.
8239// Important: this is meant to be used by a platform backend, it is reset in ImGui::NewFrame(),
8240// updated during the frame, and locked in EndFrame()/Render().
8241// If you use software rendering by setting io.MouseDrawCursor then Dear ImGui will render those for you
8247
8249{
8250 ImGuiContext& g = *GImGui;
8251 g.MouseCursor = cursor_type;
8252}
8253
8254static void UpdateAliasKey(ImGuiKey key, bool v, float analog_value)
8255{
8257 ImGuiKeyData* key_data = ImGui::GetKeyData(key);
8258 key_data->Down = v;
8259 key_data->AnalogValue = analog_value;
8260}
8261
8262// [Internal] Do not use directly
8263static ImGuiKeyChord GetMergedModsFromKeys()
8264{
8265 ImGuiKeyChord mods = 0;
8268 if (ImGui::IsKeyDown(ImGuiMod_Alt)) { mods |= ImGuiMod_Alt; }
8270 return mods;
8271}
8272
8273static void ImGui::UpdateKeyboardInputs()
8274{
8275 ImGuiContext& g = *GImGui;
8276 ImGuiIO& io = g.IO;
8277
8278 // Import legacy keys or verify they are not used
8279#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
8280 if (io.BackendUsingLegacyKeyArrays == 0)
8281 {
8282 // Backend used new io.AddKeyEvent() API: Good! Verify that old arrays are never written to externally.
8283 for (int n = 0; n < ImGuiKey_LegacyNativeKey_END; n++)
8284 IM_ASSERT((io.KeysDown[n] == false || IsKeyDown((ImGuiKey)n)) && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!");
8285 }
8286 else
8287 {
8288 if (g.FrameCount == 0)
8290 IM_ASSERT(g.IO.KeyMap[n] == -1 && "Backend is not allowed to write to io.KeyMap[0..511]!");
8291
8292 // Build reverse KeyMap (Named -> Legacy)
8293 for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_NamedKey_END; n++)
8294 if (io.KeyMap[n] != -1)
8295 {
8297 io.KeyMap[io.KeyMap[n]] = n;
8298 }
8299
8300 // Import legacy keys into new ones
8302 if (io.KeysDown[n] || io.BackendUsingLegacyKeyArrays == 1)
8303 {
8304 const ImGuiKey key = (ImGuiKey)(io.KeyMap[n] != -1 ? io.KeyMap[n] : n);
8305 IM_ASSERT(io.KeyMap[n] == -1 || IsNamedKey(key));
8306 io.KeysData[key].Down = io.KeysDown[n];
8307 if (key != n)
8308 io.KeysDown[key] = io.KeysDown[n]; // Allow legacy code using io.KeysDown[GetKeyIndex()] with old backends
8310 }
8311 if (io.BackendUsingLegacyKeyArrays == 1)
8312 {
8317 }
8318 }
8319
8320#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
8321 const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
8322 if (io.BackendUsingLegacyNavInputArray && nav_gamepad_active)
8323 {
8324 #define MAP_LEGACY_NAV_INPUT_TO_KEY1(_KEY, _NAV1) do { io.KeysData[_KEY].Down = (io.NavInputs[_NAV1] > 0.0f); io.KeysData[_KEY].AnalogValue = io.NavInputs[_NAV1]; } while (0)
8325 #define MAP_LEGACY_NAV_INPUT_TO_KEY2(_KEY, _NAV1, _NAV2) do { io.KeysData[_KEY].Down = (io.NavInputs[_NAV1] > 0.0f) || (io.NavInputs[_NAV2] > 0.0f); io.KeysData[_KEY].AnalogValue = ImMax(io.NavInputs[_NAV1], io.NavInputs[_NAV2]); } while (0)
8340 #undef NAV_MAP_KEY
8341 }
8342#endif
8343#endif
8344
8345 // Update aliases
8346 for (int n = 0; n < ImGuiMouseButton_COUNT; n++)
8347 UpdateAliasKey(MouseButtonToKey(n), io.MouseDown[n], io.MouseDown[n] ? 1.0f : 0.0f);
8348 UpdateAliasKey(ImGuiKey_MouseWheelX, io.MouseWheelH != 0.0f, io.MouseWheelH);
8349 UpdateAliasKey(ImGuiKey_MouseWheelY, io.MouseWheel != 0.0f, io.MouseWheel);
8350
8351 // Synchronize io.KeyMods and io.KeyXXX values.
8352 // - New backends (1.87+): send io.AddKeyEvent(ImGuiMod_XXX) -> -> (here) deriving io.KeyMods + io.KeyXXX from key array.
8353 // - Legacy backends: set io.KeyXXX bools -> (above) set key array from io.KeyXXX -> (here) deriving io.KeyMods + io.KeyXXX from key array.
8354 // So with legacy backends the 4 values will do a unnecessary back-and-forth but it makes the code simpler and future facing.
8355 io.KeyMods = GetMergedModsFromKeys();
8356 io.KeyCtrl = (io.KeyMods & ImGuiMod_Ctrl) != 0;
8357 io.KeyShift = (io.KeyMods & ImGuiMod_Shift) != 0;
8358 io.KeyAlt = (io.KeyMods & ImGuiMod_Alt) != 0;
8359 io.KeySuper = (io.KeyMods & ImGuiMod_Super) != 0;
8360
8361 // Clear gamepad data if disabled
8363 for (int i = ImGuiKey_Gamepad_BEGIN; i < ImGuiKey_Gamepad_END; i++)
8364 {
8365 io.KeysData[i - ImGuiKey_KeysData_OFFSET].Down = false;
8367 }
8368
8369 // Update keys
8370 for (int i = 0; i < ImGuiKey_KeysData_SIZE; i++)
8371 {
8372 ImGuiKeyData* key_data = &io.KeysData[i];
8373 key_data->DownDurationPrev = key_data->DownDuration;
8374 key_data->DownDuration = key_data->Down ? (key_data->DownDuration < 0.0f ? 0.0f : key_data->DownDuration + io.DeltaTime) : -1.0f;
8375 }
8376
8377 // Update keys/input owner (named keys only): one entry per key
8378 for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1))
8379 {
8380 ImGuiKeyData* key_data = &io.KeysData[key - ImGuiKey_KeysData_OFFSET];
8382 owner_data->OwnerCurr = owner_data->OwnerNext;
8383 if (!key_data->Down) // Important: ownership is released on the frame after a release. Ensure a 'MouseDown -> CloseWindow -> MouseUp' chain doesn't lead to someone else seeing the MouseUp.
8384 owner_data->OwnerNext = ImGuiKeyOwner_None;
8385 owner_data->LockThisFrame = owner_data->LockUntilRelease = owner_data->LockUntilRelease && key_data->Down; // Clear LockUntilRelease when key is not Down anymore
8386 }
8387
8388 UpdateKeyRoutingTable(&g.KeysRoutingTable);
8389}
8390
8391static void ImGui::UpdateMouseInputs()
8392{
8393 ImGuiContext& g = *GImGui;
8394 ImGuiIO& io = g.IO;
8395
8396 // Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well)
8397 if (IsMousePosValid(&io.MousePos))
8398 io.MousePos = g.MouseLastValidPos = ImFloorSigned(io.MousePos);
8399
8400 // If mouse just appeared or disappeared (usually denoted by -FLT_MAX components) we cancel out movement in MouseDelta
8402 io.MouseDelta = io.MousePos - io.MousePosPrev;
8403 else
8404 io.MouseDelta = ImVec2(0.0f, 0.0f);
8405
8406 // If mouse moved we re-enable mouse hovering in case it was disabled by gamepad/keyboard. In theory should use a >0.0f threshold but would need to reset in everywhere we set this to true.
8407 if (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f)
8408 g.NavDisableMouseHover = false;
8409
8410 io.MousePosPrev = io.MousePos;
8411 for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
8412 {
8413 io.MouseClicked[i] = io.MouseDown[i] && io.MouseDownDuration[i] < 0.0f;
8414 io.MouseClickedCount[i] = 0; // Will be filled below
8415 io.MouseReleased[i] = !io.MouseDown[i] && io.MouseDownDuration[i] >= 0.0f;
8417 io.MouseDownDuration[i] = io.MouseDown[i] ? (io.MouseDownDuration[i] < 0.0f ? 0.0f : io.MouseDownDuration[i] + io.DeltaTime) : -1.0f;
8418 if (io.MouseClicked[i])
8419 {
8420 bool is_repeated_click = false;
8421 if ((float)(g.Time - io.MouseClickedTime[i]) < io.MouseDoubleClickTime)
8422 {
8423 ImVec2 delta_from_click_pos = IsMousePosValid(&io.MousePos) ? (io.MousePos - io.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f);
8424 if (ImLengthSqr(delta_from_click_pos) < io.MouseDoubleClickMaxDist * io.MouseDoubleClickMaxDist)
8425 is_repeated_click = true;
8426 }
8427 if (is_repeated_click)
8428 io.MouseClickedLastCount[i]++;
8429 else
8430 io.MouseClickedLastCount[i] = 1;
8431 io.MouseClickedTime[i] = g.Time;
8432 io.MouseClickedPos[i] = io.MousePos;
8434 io.MouseDragMaxDistanceSqr[i] = 0.0f;
8435 }
8436 else if (io.MouseDown[i])
8437 {
8438 // Maintain the maximum distance we reaching from the initial click position, which is used with dragging threshold
8439 float delta_sqr_click_pos = IsMousePosValid(&io.MousePos) ? ImLengthSqr(io.MousePos - io.MouseClickedPos[i]) : 0.0f;
8440 io.MouseDragMaxDistanceSqr[i] = ImMax(io.MouseDragMaxDistanceSqr[i], delta_sqr_click_pos);
8441 }
8442
8443 // We provide io.MouseDoubleClicked[] as a legacy service
8444 io.MouseDoubleClicked[i] = (io.MouseClickedCount[i] == 2);
8445
8446 // Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation
8447 if (io.MouseClicked[i])
8448 g.NavDisableMouseHover = false;
8449 }
8450}
8451
8452static void LockWheelingWindow(ImGuiWindow* window, float wheel_amount)
8453{
8454 ImGuiContext& g = *GImGui;
8455 if (window)
8456 g.WheelingWindowReleaseTimer = ImMin(g.WheelingWindowReleaseTimer + ImAbs(wheel_amount) * WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER, WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER);
8457 else
8459 if (g.WheelingWindow == window)
8460 return;
8461 IMGUI_DEBUG_LOG_IO("LockWheelingWindow() \"%s\"\n", window ? window->Name : "NULL");
8462 g.WheelingWindow = window;
8464 if (window == NULL)
8465 {
8467 g.WheelingAxisAvg = ImVec2(0.0f, 0.0f);
8468 }
8469}
8470
8471static ImGuiWindow* FindBestWheelingWindow(const ImVec2& wheel)
8472{
8473 // For each axis, find window in the hierarchy that may want to use scrolling
8474 ImGuiContext& g = *GImGui;
8475 ImGuiWindow* windows[2] = { NULL, NULL };
8476 for (int axis = 0; axis < 2; axis++)
8477 if (wheel[axis] != 0.0f)
8478 for (ImGuiWindow* window = windows[axis] = g.HoveredWindow; window->Flags & ImGuiWindowFlags_ChildWindow; window = windows[axis] = window->ParentWindow)
8479 {
8480 // Bubble up into parent window if:
8481 // - a child window doesn't allow any scrolling.
8482 // - a child window has the ImGuiWindowFlags_NoScrollWithMouse flag.
8484 const bool has_scrolling = (window->ScrollMax[axis] != 0.0f);
8485 const bool inputs_disabled = (window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs);
8486 //const bool scrolling_past_limits = (wheel_v < 0.0f) ? (window->Scroll[axis] <= 0.0f) : (window->Scroll[axis] >= window->ScrollMax[axis]);
8487 if (has_scrolling && !inputs_disabled) // && !scrolling_past_limits)
8488 break; // select this window
8489 }
8490 if (windows[0] == NULL && windows[1] == NULL)
8491 return NULL;
8492
8493 // If there's only one window or only one axis then there's no ambiguity
8494 if (windows[0] == windows[1] || windows[0] == NULL || windows[1] == NULL)
8495 return windows[1] ? windows[1] : windows[0];
8496
8497 // If candidate are different windows we need to decide which one to prioritize
8498 // - First frame: only find a winner if one axis is zero.
8499 // - Subsequent frames: only find a winner when one is more than the other.
8500 if (g.WheelingWindowStartFrame == -1)
8502 if ((g.WheelingWindowStartFrame == g.FrameCount && wheel.x != 0.0f && wheel.y != 0.0f) || (g.WheelingAxisAvg.x == g.WheelingAxisAvg.y))
8503 {
8505 return NULL;
8506 }
8507 return (g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? windows[0] : windows[1];
8508}
8509
8510// Called by NewFrame()
8511void ImGui::UpdateMouseWheel()
8512{
8513 // Reset the locked window if we move the mouse or after the timer elapses.
8514 // FIXME: Ideally we could refactor to have one timer for "changing window w/ same axis" and a shorter timer for "changing window or axis w/ other axis" (#3795)
8515 ImGuiContext& g = *GImGui;
8516 if (g.WheelingWindow != NULL)
8517 {
8521 if (g.WheelingWindowReleaseTimer <= 0.0f)
8522 LockWheelingWindow(NULL, 0.0f);
8523 }
8524
8525 ImVec2 wheel;
8528
8529 //IMGUI_DEBUG_LOG("MouseWheel X:%.3f Y:%.3f\n", wheel_x, wheel_y);
8530 ImGuiWindow* mouse_window = g.WheelingWindow ? g.WheelingWindow : g.HoveredWindow;
8531 if (!mouse_window || mouse_window->Collapsed)
8532 return;
8533
8534 // Zoom / Scale window
8535 // FIXME-OBSOLETE: This is an old feature, it still works but pretty much nobody is using it and may be best redesigned.
8536 if (wheel.y != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling)
8537 {
8538 LockWheelingWindow(mouse_window, wheel.y);
8539 ImGuiWindow* window = mouse_window;
8540 const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f);
8541 const float scale = new_font_scale / window->FontWindowScale;
8542 window->FontWindowScale = new_font_scale;
8543 if (window == window->RootWindow)
8544 {
8545 const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size;
8546 SetWindowPos(window, window->Pos + offset, 0);
8547 window->Size = ImFloor(window->Size * scale);
8548 window->SizeFull = ImFloor(window->SizeFull * scale);
8549 }
8550 return;
8551 }
8552 if (g.IO.KeyCtrl)
8553 return;
8554
8555 // Mouse wheel scrolling
8556 // As a standard behavior holding SHIFT while using Vertical Mouse Wheel triggers Horizontal scroll instead
8557 // - We avoid doing it on OSX as it the OS input layer handles this already.
8558 // - However this means when running on OSX over Emcripten, Shift+WheelY will incur two swappings (1 in OS, 1 here), cancelling the feature.
8559 const bool swap_axis = g.IO.KeyShift && !g.IO.ConfigMacOSXBehaviors;
8560 if (swap_axis)
8561 {
8562 wheel.x = wheel.y;
8563 wheel.y = 0.0f;
8564 }
8565
8566 // Maintain a rough average of moving magnitude on both axises
8567 // FIXME: should by based on wall clock time rather than frame-counter
8568 g.WheelingAxisAvg.x = ImExponentialMovingAverage(g.WheelingAxisAvg.x, ImAbs(wheel.x), 30);
8569 g.WheelingAxisAvg.y = ImExponentialMovingAverage(g.WheelingAxisAvg.y, ImAbs(wheel.y), 30);
8570
8571 // In the rare situation where FindBestWheelingWindow() had to defer first frame of wheeling due to ambiguous main axis, reinject it now.
8573 g.WheelingWindowWheelRemainder = ImVec2(0.0f, 0.0f);
8574 if (wheel.x == 0.0f && wheel.y == 0.0f)
8575 return;
8576
8577 // Mouse wheel scrolling: find target and apply
8578 // - don't renew lock if axis doesn't apply on the window.
8579 // - select a main axis when both axises are being moved.
8580 if (ImGuiWindow* window = (g.WheelingWindow ? g.WheelingWindow : FindBestWheelingWindow(wheel)))
8581 if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))
8582 {
8583 bool do_scroll[2] = { wheel.x != 0.0f && window->ScrollMax.x != 0.0f, wheel.y != 0.0f && window->ScrollMax.y != 0.0f };
8584 if (do_scroll[ImGuiAxis_X] && do_scroll[ImGuiAxis_Y])
8585 do_scroll[(g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? ImGuiAxis_Y : ImGuiAxis_X] = false;
8586 if (do_scroll[ImGuiAxis_X])
8587 {
8588 LockWheelingWindow(window, wheel.x);
8589 float max_step = window->InnerRect.GetWidth() * 0.67f;
8590 float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step));
8591 SetScrollX(window, window->Scroll.x - wheel.x * scroll_step);
8592 }
8593 if (do_scroll[ImGuiAxis_Y])
8594 {
8595 LockWheelingWindow(window, wheel.y);
8596 float max_step = window->InnerRect.GetHeight() * 0.67f;
8597 float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step));
8598 SetScrollY(window, window->Scroll.y - wheel.y * scroll_step);
8599 }
8600 }
8601}
8602
8603void ImGui::SetNextFrameWantCaptureKeyboard(bool want_capture_keyboard)
8604{
8605 ImGuiContext& g = *GImGui;
8606 g.WantCaptureKeyboardNextFrame = want_capture_keyboard ? 1 : 0;
8607}
8608
8609void ImGui::SetNextFrameWantCaptureMouse(bool want_capture_mouse)
8610{
8611 ImGuiContext& g = *GImGui;
8612 g.WantCaptureMouseNextFrame = want_capture_mouse ? 1 : 0;
8613}
8614
8615#ifndef IMGUI_DISABLE_DEBUG_TOOLS
8616static const char* GetInputSourceName(ImGuiInputSource source)
8617{
8618 const char* input_source_names[] = { "None", "Mouse", "Keyboard", "Gamepad", "Nav", "Clipboard" };
8619 IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT && source >= 0 && source < ImGuiInputSource_COUNT);
8620 return input_source_names[source];
8621}
8622static void DebugPrintInputEvent(const char* prefix, const ImGuiInputEvent* e)
8623{
8624 ImGuiContext& g = *GImGui;
8625 if (e->Type == ImGuiInputEventType_MousePos) { if (e->MousePos.PosX == -FLT_MAX && e->MousePos.PosY == -FLT_MAX) IMGUI_DEBUG_LOG_IO("%s: MousePos (-FLT_MAX, -FLT_MAX)\n", prefix); else IMGUI_DEBUG_LOG_IO("%s: MousePos (%.1f, %.1f)\n", prefix, e->MousePos.PosX, e->MousePos.PosY); return; }
8626 if (e->Type == ImGuiInputEventType_MouseButton) { IMGUI_DEBUG_LOG_IO("%s: MouseButton %d %s\n", prefix, e->MouseButton.Button, e->MouseButton.Down ? "Down" : "Up"); return; }
8627 if (e->Type == ImGuiInputEventType_MouseWheel) { IMGUI_DEBUG_LOG_IO("%s: MouseWheel (%.3f, %.3f)\n", prefix, e->MouseWheel.WheelX, e->MouseWheel.WheelY); return; }
8628 if (e->Type == ImGuiInputEventType_Key) { IMGUI_DEBUG_LOG_IO("%s: Key \"%s\" %s\n", prefix, ImGui::GetKeyName(e->Key.Key), e->Key.Down ? "Down" : "Up"); return; }
8629 if (e->Type == ImGuiInputEventType_Text) { IMGUI_DEBUG_LOG_IO("%s: Text: %c (U+%08X)\n", prefix, e->Text.Char, e->Text.Char); return; }
8630 if (e->Type == ImGuiInputEventType_Focus) { IMGUI_DEBUG_LOG_IO("%s: AppFocused %d\n", prefix, e->AppFocused.Focused); return; }
8631}
8632#endif
8633
8634// Process input queue
8635// We always call this with the value of 'bool g.IO.ConfigInputTrickleEventQueue'.
8636// - trickle_fast_inputs = false : process all events, turn into flattened input state (e.g. successive down/up/down/up will be lost)
8637// - trickle_fast_inputs = true : process as many events as possible (successive down/up/down/up will be trickled over several frames so nothing is lost) (new feature in 1.87)
8638void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
8639{
8640 ImGuiContext& g = *GImGui;
8641 ImGuiIO& io = g.IO;
8642
8643 // Only trickle chars<>key when working with InputText()
8644 // FIXME: InputText() could parse event trail?
8645 // FIXME: Could specialize chars<>keys trickling rules for control keys (those not typically associated to characters)
8646 const bool trickle_interleaved_keys_and_text = (trickle_fast_inputs && g.WantTextInputNextFrame == 1);
8647
8648 bool mouse_moved = false, mouse_wheeled = false, key_changed = false, text_inputted = false;
8649 int mouse_button_changed = 0x00;
8650 ImBitArray<ImGuiKey_KeysData_SIZE> key_changed_mask;
8651
8652 int event_n = 0;
8653 for (; event_n < g.InputEventsQueue.Size; event_n++)
8654 {
8655 ImGuiInputEvent* e = &g.InputEventsQueue[event_n];
8657 {
8658 // Trickling Rule: Stop processing queued events if we already handled a mouse button change
8659 ImVec2 event_pos(e->MousePos.PosX, e->MousePos.PosY);
8660 if (trickle_fast_inputs && (mouse_button_changed != 0 || mouse_wheeled || key_changed || text_inputted))
8661 break;
8662 io.MousePos = event_pos;
8663 mouse_moved = true;
8664 }
8666 {
8667 // Trickling Rule: Stop processing queued events if we got multiple action on the same button
8668 const ImGuiMouseButton button = e->MouseButton.Button;
8669 IM_ASSERT(button >= 0 && button < ImGuiMouseButton_COUNT);
8670 if (trickle_fast_inputs && ((mouse_button_changed & (1 << button)) || mouse_wheeled))
8671 break;
8672 io.MouseDown[button] = e->MouseButton.Down;
8673 mouse_button_changed |= (1 << button);
8674 }
8675 else if (e->Type == ImGuiInputEventType_MouseWheel)
8676 {
8677 // Trickling Rule: Stop processing queued events if we got multiple action on the event
8678 if (trickle_fast_inputs && (mouse_moved || mouse_button_changed != 0))
8679 break;
8680 io.MouseWheelH += e->MouseWheel.WheelX;
8681 io.MouseWheel += e->MouseWheel.WheelY;
8682 mouse_wheeled = true;
8683 }
8684 else if (e->Type == ImGuiInputEventType_Key)
8685 {
8686 // Trickling Rule: Stop processing queued events if we got multiple action on the same button
8687 ImGuiKey key = e->Key.Key;
8688 IM_ASSERT(key != ImGuiKey_None);
8689 ImGuiKeyData* key_data = GetKeyData(key);
8690 const int key_data_index = (int)(key_data - g.IO.KeysData);
8691 if (trickle_fast_inputs && key_data->Down != e->Key.Down && (key_changed_mask.TestBit(key_data_index) || text_inputted || mouse_button_changed != 0))
8692 break;
8693 key_data->Down = e->Key.Down;
8694 key_data->AnalogValue = e->Key.AnalogValue;
8695 key_changed = true;
8696 key_changed_mask.SetBit(key_data_index);
8697
8698 // Allow legacy code using io.KeysDown[GetKeyIndex()] with new backends
8699#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
8700 io.KeysDown[key_data_index] = key_data->Down;
8701 if (io.KeyMap[key_data_index] != -1)
8702 io.KeysDown[io.KeyMap[key_data_index]] = key_data->Down;
8703#endif
8704 }
8705 else if (e->Type == ImGuiInputEventType_Text)
8706 {
8707 // Trickling Rule: Stop processing queued events if keys/mouse have been interacted with
8708 if (trickle_fast_inputs && ((key_changed && trickle_interleaved_keys_and_text) || mouse_button_changed != 0 || mouse_moved || mouse_wheeled))
8709 break;
8710 unsigned int c = e->Text.Char;
8712 if (trickle_interleaved_keys_and_text)
8713 text_inputted = true;
8714 }
8715 else if (e->Type == ImGuiInputEventType_Focus)
8716 {
8717 // We intentionally overwrite this and process in NewFrame(), in order to give a chance
8718 // to multi-viewports backends to queue AddFocusEvent(false) + AddFocusEvent(true) in same frame.
8719 const bool focus_lost = !e->AppFocused.Focused;
8720 io.AppFocusLost = focus_lost;
8721 }
8722 else
8723 {
8724 IM_ASSERT(0 && "Unknown event!");
8725 }
8726 }
8727
8728 // Record trail (for domain-specific applications wanting to access a precise trail)
8729 //if (event_n != 0) IMGUI_DEBUG_LOG_IO("Processed: %d / Remaining: %d\n", event_n, g.InputEventsQueue.Size - event_n);
8730 for (int n = 0; n < event_n; n++)
8732
8733 // [DEBUG]
8734#ifndef IMGUI_DISABLE_DEBUG_TOOLS
8735 if (event_n != 0 && (g.DebugLogFlags & ImGuiDebugLogFlags_EventIO))
8736 for (int n = 0; n < g.InputEventsQueue.Size; n++)
8737 DebugPrintInputEvent(n < event_n ? "Processed" : "Remaining", &g.InputEventsQueue[n]);
8738#endif
8739
8740 // Remaining events will be processed on the next frame
8741 if (event_n == g.InputEventsQueue.Size)
8743 else
8745
8746 // Clear buttons state when focus is lost
8747 // - this is useful so e.g. releasing Alt after focus loss on Alt-Tab doesn't trigger the Alt menu toggle.
8748 // - we clear in EndFrame() and not now in order allow application/user code polling this flag
8749 // (e.g. custom backend may want to clear additional data, custom widgets may want to react with a "canceling" event).
8750 if (g.IO.AppFocusLost)
8751 g.IO.ClearInputKeys();
8752}
8753
8755{
8756 if (!IsNamedKeyOrModKey(key))
8757 return ImGuiKeyOwner_None;
8758
8759 ImGuiContext& g = *GImGui;
8760 ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(key);
8761 ImGuiID owner_id = owner_data->OwnerCurr;
8762
8763 if (g.ActiveIdUsingAllKeyboardKeys && owner_id != g.ActiveId && owner_id != ImGuiKeyOwner_Any)
8765 return ImGuiKeyOwner_None;
8766
8767 return owner_id;
8768}
8769
8770// TestKeyOwner(..., ID) : (owner == None || owner == ID)
8771// TestKeyOwner(..., None) : (owner == None)
8772// TestKeyOwner(..., Any) : no owner test
8773// All paths are also testing for key not being locked, for the rare cases that key have been locked with using ImGuiInputFlags_LockXXX flags.
8775{
8776 if (!IsNamedKeyOrModKey(key))
8777 return true;
8778
8779 ImGuiContext& g = *GImGui;
8780 if (g.ActiveIdUsingAllKeyboardKeys && owner_id != g.ActiveId && owner_id != ImGuiKeyOwner_Any)
8782 return false;
8783
8784 ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(key);
8785 if (owner_id == ImGuiKeyOwner_Any)
8786 return (owner_data->LockThisFrame == false);
8787
8788 // Note: SetKeyOwner() sets OwnerCurr. It is not strictly required for most mouse routing overlap (because of ActiveId/HoveredId
8789 // are acting as filter before this has a chance to filter), but sane as soon as user tries to look into things.
8790 // Setting OwnerCurr in SetKeyOwner() is more consistent than testing OwnerNext here: would be inconsistent with getter and other functions.
8791 if (owner_data->OwnerCurr != owner_id)
8792 {
8793 if (owner_data->LockThisFrame)
8794 return false;
8795 if (owner_data->OwnerCurr != ImGuiKeyOwner_None)
8796 return false;
8797 }
8798
8799 return true;
8800}
8801
8802// _LockXXX flags are useful to lock keys away from code which is not input-owner aware.
8803// When using _LockXXX flags, you can use ImGuiKeyOwner_Any to lock keys from everyone.
8804// - SetKeyOwner(..., None) : clears owner
8805// - SetKeyOwner(..., Any, !Lock) : illegal (assert)
8806// - SetKeyOwner(..., Any or None, Lock) : set lock
8808{
8809 IM_ASSERT(IsNamedKeyOrModKey(key) && (owner_id != ImGuiKeyOwner_Any || (flags & (ImGuiInputFlags_LockThisFrame | ImGuiInputFlags_LockUntilRelease)))); // Can only use _Any with _LockXXX flags (to eat a key away without an ID to retrieve it)
8810 IM_ASSERT((flags & ~ImGuiInputFlags_SupportedBySetKeyOwner) == 0); // Passing flags not supported by this function!
8811
8812 ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(key);
8813 owner_data->OwnerCurr = owner_data->OwnerNext = owner_id;
8814
8815 // We cannot lock by default as it would likely break lots of legacy code.
8816 // In the case of using LockUntilRelease while key is not down we still lock during the frame (no key_data->Down test)
8817 owner_data->LockUntilRelease = (flags & ImGuiInputFlags_LockUntilRelease) != 0;
8818 owner_data->LockThisFrame = (flags & ImGuiInputFlags_LockThisFrame) != 0 || (owner_data->LockUntilRelease);
8819}
8820
8821// This is more or less equivalent to:
8822// if (IsItemHovered() || IsItemActive())
8823// SetKeyOwner(key, GetItemID());
8824// Extensive uses of that (e.g. many calls for a single item) may want to manually perform the tests once and then call SetKeyOwner() multiple times.
8825// More advanced usage scenarios may want to call SetKeyOwner() manually based on different condition.
8826// Worth noting is that only one item can be hovered and only one item can be active, therefore this usage pattern doesn't need to bother with routing and priority.
8828{
8829 ImGuiContext& g = *GImGui;
8830 ImGuiID id = g.LastItemData.ID;
8831 if (id == 0 || (g.HoveredId != id && g.ActiveId != id))
8832 return;
8833 if ((flags & ImGuiInputFlags_CondMask_) == 0)
8835 if ((g.HoveredId == id && (flags & ImGuiInputFlags_CondHovered)) || (g.ActiveId == id && (flags & ImGuiInputFlags_CondActive)))
8836 {
8837 IM_ASSERT((flags & ~ImGuiInputFlags_SupportedBySetItemKeyOwner) == 0); // Passing flags not supported by this function!
8838 SetKeyOwner(key, id, flags & ~ImGuiInputFlags_CondMask_);
8839 }
8840}
8841
8843{
8844 ImGuiContext& g = *GImGui;
8845
8846 // When using (owner_id == 0/Any): SetShortcutRouting() will use CurrentFocusScopeId and filter with this, so IsKeyPressed() is fine with he 0/Any.
8847 if ((flags & ImGuiInputFlags_RouteMask_) == 0)
8849 if (!SetShortcutRouting(key_chord, owner_id, flags))
8850 return false;
8851
8852 if (key_chord & ImGuiMod_Shortcut)
8853 key_chord = ConvertShortcutMod(key_chord);
8854 ImGuiKey mods = (ImGuiKey)(key_chord & ImGuiMod_Mask_);
8855 if (g.IO.KeyMods != mods)
8856 return false;
8857
8858 // Special storage location for mods
8859 ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_);
8860 if (key == ImGuiKey_None)
8861 key = ConvertSingleModFlagToKey(mods);
8862
8864 return false;
8865 IM_ASSERT((flags & ~ImGuiInputFlags_SupportedByShortcut) == 0); // Passing flags not supported by this function!
8866
8867 return true;
8868}
8869
8870
8871//-----------------------------------------------------------------------------
8872// [SECTION] ERROR CHECKING
8873//-----------------------------------------------------------------------------
8874
8875// Helper function to verify ABI compatibility between caller code and compiled version of Dear ImGui.
8876// Verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit
8877// If this triggers you have an issue:
8878// - Most commonly: mismatched headers and compiled code version.
8879// - Or: mismatched configuration #define, compilation settings, packing pragma etc.
8880// The configuration settings mentioned in imconfig.h must be set for all compilation units involved with Dear ImGui,
8881// which is way it is required you put them in your imconfig file (and not just before including imgui.h).
8882// Otherwise it is possible that different compilation units would see different structure layout
8883bool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_vert, size_t sz_idx)
8884{
8885 bool error = false;
8886 if (strcmp(version, IMGUI_VERSION) != 0) { error = true; IM_ASSERT(strcmp(version, IMGUI_VERSION) == 0 && "Mismatched version string!"); }
8887 if (sz_io != sizeof(ImGuiIO)) { error = true; IM_ASSERT(sz_io == sizeof(ImGuiIO) && "Mismatched struct layout!"); }
8888 if (sz_style != sizeof(ImGuiStyle)) { error = true; IM_ASSERT(sz_style == sizeof(ImGuiStyle) && "Mismatched struct layout!"); }
8889 if (sz_vec2 != sizeof(ImVec2)) { error = true; IM_ASSERT(sz_vec2 == sizeof(ImVec2) && "Mismatched struct layout!"); }
8890 if (sz_vec4 != sizeof(ImVec4)) { error = true; IM_ASSERT(sz_vec4 == sizeof(ImVec4) && "Mismatched struct layout!"); }
8891 if (sz_vert != sizeof(ImDrawVert)) { error = true; IM_ASSERT(sz_vert == sizeof(ImDrawVert) && "Mismatched struct layout!"); }
8892 if (sz_idx != sizeof(ImDrawIdx)) { error = true; IM_ASSERT(sz_idx == sizeof(ImDrawIdx) && "Mismatched struct layout!"); }
8893 return !error;
8894}
8895
8896// Until 1.89 (IMGUI_VERSION_NUM < 18814) it was legal to use SetCursorPos() to extend the boundary of a parent (e.g. window or table cell)
8897// This is causing issues and ambiguity and we need to retire that.
8898// See https://github.com/ocornut/imgui/issues/5548 for more details.
8899// [Scenario 1]
8900// Previously this would make the window content size ~200x200:
8901// Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + End(); // NOT OK
8902// Instead, please submit an item:
8903// Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + Dummy(ImVec2(0,0)) + End(); // OK
8904// Alternative:
8905// Begin(...) + Dummy(ImVec2(200,200)) + End(); // OK
8906// [Scenario 2]
8907// For reference this is one of the issue what we aim to fix with this change:
8908// BeginGroup() + SomeItem("foobar") + SetCursorScreenPos(GetCursorScreenPos()) + EndGroup()
8909// The previous logic made SetCursorScreenPos(GetCursorScreenPos()) have a side-effect! It would erroneously incorporate ItemSpacing.y after the item into content size, making the group taller!
8910// While this code is a little twisted, no-one would expect SetXXX(GetXXX()) to have a side-effect. Using vertical alignment patterns could trigger this issue.
8912{
8913 ImGuiContext& g = *GImGui;
8914 ImGuiWindow* window = g.CurrentWindow;
8915 IM_ASSERT(window->DC.IsSetPos);
8916 window->DC.IsSetPos = false;
8917#ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
8918 if (window->DC.CursorPos.x <= window->DC.CursorMaxPos.x && window->DC.CursorPos.y <= window->DC.CursorMaxPos.y)
8919 return;
8920 if (window->SkipItems)
8921 return;
8922 IM_ASSERT(0 && "Code uses SetCursorPos()/SetCursorScreenPos() to extend window/parent boundaries. Please submit an item e.g. Dummy() to validate extent.");
8923#else
8924 window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
8925#endif
8926}
8927
8928static void ImGui::ErrorCheckNewFrameSanityChecks()
8929{
8930 ImGuiContext& g = *GImGui;
8931
8932 // Check user IM_ASSERT macro
8933 // (IF YOU GET A WARNING OR COMPILE ERROR HERE: it means your assert macro is incorrectly defined!
8934 // If your macro uses multiple statements, it NEEDS to be surrounded by a 'do { ... } while (0)' block.
8935 // This is a common C/C++ idiom to allow multiple statements macros to be used in control flow blocks.)
8936 // #define IM_ASSERT(EXPR) if (SomeCode(EXPR)) SomeMoreCode(); // Wrong!
8937 // #define IM_ASSERT(EXPR) do { if (SomeCode(EXPR)) SomeMoreCode(); } while (0) // Correct!
8938 if (true) IM_ASSERT(1); else IM_ASSERT(0);
8939
8940 // Emscripten backends are often imprecise in their submission of DeltaTime. (#6114, #3644)
8941 // Ideally the Emscripten app/backend should aim to fix or smooth this value and avoid feeding zero, but we tolerate it.
8942#ifdef __EMSCRIPTEN__
8943 if (g.IO.DeltaTime <= 0.0f && g.FrameCount > 0)
8944 g.IO.DeltaTime = 0.00001f;
8945#endif
8946
8947 // Check user data
8948 // (We pass an error message in the assert expression to make it visible to programmers who are not using a debugger, as most assert handlers display their argument)
8950 IM_ASSERT((g.IO.DeltaTime > 0.0f || g.FrameCount == 0) && "Need a positive DeltaTime!");
8951 IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount) && "Forgot to call Render() or EndFrame() at the end of the previous frame?");
8952 IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f && "Invalid DisplaySize value!");
8953 IM_ASSERT(g.IO.Fonts->IsBuilt() && "Font Atlas not built! Make sure you called ImGui_ImplXXXX_NewFrame() function for renderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()");
8954 IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting!");
8955 IM_ASSERT(g.Style.CircleTessellationMaxError > 0.0f && "Invalid style setting!");
8956 IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting!"); // Allows us to avoid a few clamps in color computations
8957 IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting.");
8960#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
8961 for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_COUNT; n++)
8962 IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < ImGuiKey_LegacyNativeKey_END && "io.KeyMap[] contains an out of bound value (need to be 0..511, or -1 for unmapped key)");
8963
8964 // Check: required key mapping (we intentionally do NOT check all keys to not pressure user into setting up everything, but Space is required and was only added in 1.60 WIP)
8966 IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation.");
8967#endif
8968
8969 // Check: the io.ConfigWindowsResizeFromEdges option requires backend to honor mouse cursor changes and set the ImGuiBackendFlags_HasMouseCursors flag accordingly.
8972}
8973
8974static void ImGui::ErrorCheckEndFrameSanityChecks()
8975{
8976 ImGuiContext& g = *GImGui;
8977
8978 // Verify that io.KeyXXX fields haven't been tampered with. Key mods should not be modified between NewFrame() and EndFrame()
8979 // One possible reason leading to this assert is that your backends update inputs _AFTER_ NewFrame().
8980 // It is known that when some modal native windows called mid-frame takes focus away, some backends such as GLFW will
8981 // send key release events mid-frame. This would normally trigger this assertion and lead to sheared inputs.
8982 // We silently accommodate for this case by ignoring the case where all io.KeyXXX modifiers were released (aka key_mod_flags == 0),
8983 // while still correctly asserting on mid-frame key press events.
8984 const ImGuiKeyChord key_mods = GetMergedModsFromKeys();
8985 IM_ASSERT((key_mods == 0 || g.IO.KeyMods == key_mods) && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods");
8986 IM_UNUSED(key_mods);
8987
8988 // [EXPERIMENTAL] Recover from errors: You may call this yourself before EndFrame().
8989 //ErrorCheckEndFrameRecover();
8990
8991 // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you
8992 // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API).
8993 if (g.CurrentWindowStack.Size != 1)
8994 {
8995 if (g.CurrentWindowStack.Size > 1)
8996 {
8997 IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?");
8998 while (g.CurrentWindowStack.Size > 1)
8999 End();
9000 }
9001 else
9002 {
9003 IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?");
9004 }
9005 }
9006
9007 IM_ASSERT_USER_ERROR(g.GroupStack.Size == 0, "Missing EndGroup call!");
9008}
9009
9010// Experimental recovery from incorrect usage of BeginXXX/EndXXX/PushXXX/PopXXX calls.
9011// Must be called during or before EndFrame().
9012// This is generally flawed as we are not necessarily End/Popping things in the right order.
9013// FIXME: Can't recover from inside BeginTabItem/EndTabItem yet.
9014// FIXME: Can't recover from interleaved BeginTabBar/Begin
9016{
9017 // PVS-Studio V1044 is "Loop break conditions do not depend on the number of iterations"
9018 ImGuiContext& g = *GImGui;
9019 while (g.CurrentWindowStack.Size > 0) //-V1044
9020 {
9021 ErrorCheckEndWindowRecover(log_callback, user_data);
9022 ImGuiWindow* window = g.CurrentWindow;
9023 if (g.CurrentWindowStack.Size == 1)
9024 {
9025 IM_ASSERT(window->IsFallbackWindow);
9026 break;
9027 }
9028 if (window->Flags & ImGuiWindowFlags_ChildWindow)
9029 {
9030 if (log_callback) log_callback(user_data, "Recovered from missing EndChild() for '%s'", window->Name);
9031 EndChild();
9032 }
9033 else
9034 {
9035 if (log_callback) log_callback(user_data, "Recovered from missing End() for '%s'", window->Name);
9036 End();
9037 }
9038 }
9039}
9040
9041// Must be called before End()/EndChild()
9043{
9044 ImGuiContext& g = *GImGui;
9046 {
9047 if (log_callback) log_callback(user_data, "Recovered from missing EndTable() in '%s'", g.CurrentTable->OuterWindow->Name);
9048 EndTable();
9049 }
9050
9051 ImGuiWindow* window = g.CurrentWindow;
9053 IM_ASSERT(window != NULL);
9054 while (g.CurrentTabBar != NULL) //-V1044
9055 {
9056 if (log_callback) log_callback(user_data, "Recovered from missing EndTabBar() in '%s'", window->Name);
9057 EndTabBar();
9058 }
9059 while (window->DC.TreeDepth > 0)
9060 {
9061 if (log_callback) log_callback(user_data, "Recovered from missing TreePop() in '%s'", window->Name);
9062 TreePop();
9063 }
9064 while (g.GroupStack.Size > stack_sizes->SizeOfGroupStack) //-V1044
9065 {
9066 if (log_callback) log_callback(user_data, "Recovered from missing EndGroup() in '%s'", window->Name);
9067 EndGroup();
9068 }
9069 while (window->IDStack.Size > 1)
9070 {
9071 if (log_callback) log_callback(user_data, "Recovered from missing PopID() in '%s'", window->Name);
9072 PopID();
9073 }
9074 while (g.DisabledStackSize > stack_sizes->SizeOfDisabledStack) //-V1044
9075 {
9076 if (log_callback) log_callback(user_data, "Recovered from missing EndDisabled() in '%s'", window->Name);
9077 EndDisabled();
9078 }
9079 while (g.ColorStack.Size > stack_sizes->SizeOfColorStack)
9080 {
9081 if (log_callback) log_callback(user_data, "Recovered from missing PopStyleColor() in '%s' for ImGuiCol_%s", window->Name, GetStyleColorName(g.ColorStack.back().Col));
9082 PopStyleColor();
9083 }
9084 while (g.ItemFlagsStack.Size > stack_sizes->SizeOfItemFlagsStack) //-V1044
9085 {
9086 if (log_callback) log_callback(user_data, "Recovered from missing PopItemFlag() in '%s'", window->Name);
9087 PopItemFlag();
9088 }
9089 while (g.StyleVarStack.Size > stack_sizes->SizeOfStyleVarStack) //-V1044
9090 {
9091 if (log_callback) log_callback(user_data, "Recovered from missing PopStyleVar() in '%s'", window->Name);
9092 PopStyleVar();
9093 }
9094 while (g.FocusScopeStack.Size > stack_sizes->SizeOfFocusScopeStack + 1) //-V1044
9095 {
9096 if (log_callback) log_callback(user_data, "Recovered from missing PopFocusScope() in '%s'", window->Name);
9097 PopFocusScope();
9098 }
9099}
9100
9101// Save current stack sizes for later compare
9116
9117// Compare to detect usage errors
9119{
9120 ImGuiContext& g = *ctx;
9121 ImGuiWindow* window = g.CurrentWindow;
9122 IM_UNUSED(window);
9123
9124 // Window stacks
9125 // NOT checking: DC.ItemWidth, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin)
9126 IM_ASSERT(SizeOfIDStack == window->IDStack.Size && "PushID/PopID or TreeNode/TreePop Mismatch!");
9127
9128 // Global stacks
9129 // For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them.
9130 IM_ASSERT(SizeOfGroupStack == g.GroupStack.Size && "BeginGroup/EndGroup Mismatch!");
9131 IM_ASSERT(SizeOfBeginPopupStack == g.BeginPopupStack.Size && "BeginPopup/EndPopup or BeginMenu/EndMenu Mismatch!");
9132 IM_ASSERT(SizeOfDisabledStack == g.DisabledStackSize && "BeginDisabled/EndDisabled Mismatch!");
9133 IM_ASSERT(SizeOfItemFlagsStack >= g.ItemFlagsStack.Size && "PushItemFlag/PopItemFlag Mismatch!");
9134 IM_ASSERT(SizeOfColorStack >= g.ColorStack.Size && "PushStyleColor/PopStyleColor Mismatch!");
9135 IM_ASSERT(SizeOfStyleVarStack >= g.StyleVarStack.Size && "PushStyleVar/PopStyleVar Mismatch!");
9136 IM_ASSERT(SizeOfFontStack >= g.FontStack.Size && "PushFont/PopFont Mismatch!");
9137 IM_ASSERT(SizeOfFocusScopeStack == g.FocusScopeStack.Size && "PushFocusScope/PopFocusScope Mismatch!");
9138}
9139
9140
9141//-----------------------------------------------------------------------------
9142// [SECTION] LAYOUT
9143//-----------------------------------------------------------------------------
9144// - ItemSize()
9145// - ItemAdd()
9146// - SameLine()
9147// - GetCursorScreenPos()
9148// - SetCursorScreenPos()
9149// - GetCursorPos(), GetCursorPosX(), GetCursorPosY()
9150// - SetCursorPos(), SetCursorPosX(), SetCursorPosY()
9151// - GetCursorStartPos()
9152// - Indent()
9153// - Unindent()
9154// - SetNextItemWidth()
9155// - PushItemWidth()
9156// - PushMultiItemsWidths()
9157// - PopItemWidth()
9158// - CalcItemWidth()
9159// - CalcItemSize()
9160// - GetTextLineHeight()
9161// - GetTextLineHeightWithSpacing()
9162// - GetFrameHeight()
9163// - GetFrameHeightWithSpacing()
9164// - GetContentRegionMax()
9165// - GetContentRegionMaxAbs() [Internal]
9166// - GetContentRegionAvail(),
9167// - GetWindowContentRegionMin(), GetWindowContentRegionMax()
9168// - BeginGroup()
9169// - EndGroup()
9170// Also see in imgui_widgets: tab bars, and in imgui_tables: tables, columns.
9171//-----------------------------------------------------------------------------
9172
9173// Advance cursor given item size for layout.
9174// Register minimum needed size so it can extend the bounding box used for auto-fit calculation.
9175// See comments in ItemAdd() about how/why the size provided to ItemSize() vs ItemAdd() may often different.
9176void ImGui::ItemSize(const ImVec2& size, float text_baseline_y)
9177{
9178 ImGuiContext& g = *GImGui;
9179 ImGuiWindow* window = g.CurrentWindow;
9180 if (window->SkipItems)
9181 return;
9182
9183 // We increase the height in this function to accommodate for baseline offset.
9184 // In theory we should be offsetting the starting position (window->DC.CursorPos), that will be the topic of a larger refactor,
9185 // but since ItemSize() is not yet an API that moves the cursor (to handle e.g. wrapping) enlarging the height has the same effect.
9186 const float offset_to_match_baseline_y = (text_baseline_y >= 0) ? ImMax(0.0f, window->DC.CurrLineTextBaseOffset - text_baseline_y) : 0.0f;
9187
9188 const float line_y1 = window->DC.IsSameLine ? window->DC.CursorPosPrevLine.y : window->DC.CursorPos.y;
9189 const float line_height = ImMax(window->DC.CurrLineSize.y, /*ImMax(*/window->DC.CursorPos.y - line_y1/*, 0.0f)*/ + size.y + offset_to_match_baseline_y);
9190
9191 // Always align ourselves on pixel boundaries
9192 //if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG]
9193 window->DC.CursorPosPrevLine.x = window->DC.CursorPos.x + size.x;
9194 window->DC.CursorPosPrevLine.y = line_y1;
9195 window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); // Next line
9196 window->DC.CursorPos.y = IM_FLOOR(line_y1 + line_height + g.Style.ItemSpacing.y); // Next line
9197 window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x);
9198 window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y);
9199 //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG]
9200
9201 window->DC.PrevLineSize.y = line_height;
9202 window->DC.CurrLineSize.y = 0.0f;
9203 window->DC.PrevLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, text_baseline_y);
9204 window->DC.CurrLineTextBaseOffset = 0.0f;
9205 window->DC.IsSameLine = window->DC.IsSetPos = false;
9206
9207 // Horizontal layout mode
9209 SameLine();
9210}
9211
9212// Declare item bounding box for clipping and interaction.
9213// Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface
9214// declare their minimum size requirement to ItemSize() and provide a larger region to ItemAdd() which is used drawing/interaction.
9215bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGuiItemFlags extra_flags)
9216{
9217 ImGuiContext& g = *GImGui;
9218 ImGuiWindow* window = g.CurrentWindow;
9219
9220 // Set item data
9221 // (DisplayRect is left untouched, made valid when ImGuiItemStatusFlags_HasDisplayRect is set)
9222 g.LastItemData.ID = id;
9223 g.LastItemData.Rect = bb;
9224 g.LastItemData.NavRect = nav_bb_arg ? *nav_bb_arg : bb;
9225 g.LastItemData.InFlags = g.CurrentItemFlags | extra_flags;
9227
9228 // Directional navigation processing
9229 if (id != 0)
9230 {
9231 KeepAliveID(id);
9232
9233 // Runs prior to clipping early-out
9234 // (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget
9235 // (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests
9236 // unfortunately, but it is still limited to one window. It may not scale very well for windows with ten of
9237 // thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame.
9238 // We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able
9239 // to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick).
9240 // We intentionally don't check if g.NavWindow != NULL because g.NavAnyRequest should only be set when it is non null.
9241 // If we crash on a NULL g.NavWindow we need to fix the bug elsewhere.
9243 {
9244 window->DC.NavLayersActiveMaskNext |= (1 << window->DC.NavLayerCurrent);
9245 if (g.NavId == id || g.NavAnyRequest)
9247 if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened))
9248 NavProcessItem();
9249 }
9250
9251 // [DEBUG] People keep stumbling on this problem and using "" as identifier in the root of a window instead of "##something".
9252 // Empty identifier are valid and useful in a small amount of cases, but 99.9% of the time you want to use "##something".
9253 // READ THE FAQ: https://dearimgui.org/faq
9254 IM_ASSERT(id != window->ID && "Cannot have an empty ID at the root of a window. If you need an empty label, use ## and read the FAQ about how the ID Stack works!");
9255 }
9257
9258#ifdef IMGUI_ENABLE_TEST_ENGINE
9259 if (id != 0)
9261#endif
9262
9263 // Clipping test
9264 // (FIXME: This is a modified copy of IsClippedEx() so we can reuse the is_rect_visible value)
9265 //const bool is_clipped = IsClippedEx(bb, id);
9266 //if (is_clipped)
9267 // return false;
9268 const bool is_rect_visible = bb.Overlaps(window->ClipRect);
9269 if (!is_rect_visible)
9270 if (id == 0 || (id != g.ActiveId && id != g.NavId))
9271 if (!g.LogEnabled)
9272 return false;
9273
9274 // [DEBUG]
9275#ifndef IMGUI_DISABLE_DEBUG_TOOLS
9276 if (id != 0 && id == g.DebugLocateId)
9278#endif
9279 //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG]
9280
9281 // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them)
9282 if (is_rect_visible)
9284 if (IsMouseHoveringRect(bb.Min, bb.Max))
9286 return true;
9287}
9288
9289// Gets back to previous line and continue with horizontal layout
9290// offset_from_start_x == 0 : follow right after previous item
9291// offset_from_start_x != 0 : align to specified x position (relative to window/group left)
9292// spacing_w < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0
9293// spacing_w >= 0 : enforce spacing amount
9294void ImGui::SameLine(float offset_from_start_x, float spacing_w)
9295{
9296 ImGuiContext& g = *GImGui;
9297 ImGuiWindow* window = g.CurrentWindow;
9298 if (window->SkipItems)
9299 return;
9300
9301 if (offset_from_start_x != 0.0f)
9302 {
9303 if (spacing_w < 0.0f)
9304 spacing_w = 0.0f;
9305 window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + offset_from_start_x + spacing_w + window->DC.GroupOffset.x + window->DC.ColumnsOffset.x;
9306 window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
9307 }
9308 else
9309 {
9310 if (spacing_w < 0.0f)
9311 spacing_w = g.Style.ItemSpacing.x;
9312 window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w;
9313 window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
9314 }
9315 window->DC.CurrLineSize = window->DC.PrevLineSize;
9317 window->DC.IsSameLine = true;
9318}
9319
9321{
9323 return window->DC.CursorPos;
9324}
9325
9326// 2022/08/05: Setting cursor position also extend boundaries (via modifying CursorMaxPos) used to compute window size, group size etc.
9327// I believe this was is a judicious choice but it's probably being relied upon (it has been the case since 1.31 and 1.50)
9328// It would be sane if we requested user to use SetCursorPos() + Dummy(ImVec2(0,0)) to extend CursorMaxPos...
9330{
9331 ImGuiWindow* window = GetCurrentWindow();
9332 window->DC.CursorPos = pos;
9333 //window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
9334 window->DC.IsSetPos = true;
9335}
9336
9337// User generally sees positions in window coordinates. Internally we store CursorPos in absolute screen coordinates because it is more convenient.
9338// Conversion happens as we pass the value to user, but it makes our naming convention confusing because GetCursorPos() == (DC.CursorPos - window.Pos). May want to rename 'DC.CursorPos'.
9340{
9342 return window->DC.CursorPos - window->Pos + window->Scroll;
9343}
9344
9346{
9348 return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x;
9349}
9350
9352{
9354 return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y;
9355}
9356
9357void ImGui::SetCursorPos(const ImVec2& local_pos)
9358{
9359 ImGuiWindow* window = GetCurrentWindow();
9360 window->DC.CursorPos = window->Pos - window->Scroll + local_pos;
9361 //window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
9362 window->DC.IsSetPos = true;
9363}
9364
9366{
9367 ImGuiWindow* window = GetCurrentWindow();
9368 window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x;
9369 //window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x);
9370 window->DC.IsSetPos = true;
9371}
9372
9374{
9375 ImGuiWindow* window = GetCurrentWindow();
9376 window->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y;
9377 //window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y);
9378 window->DC.IsSetPos = true;
9379}
9380
9382{
9384 return window->DC.CursorStartPos - window->Pos;
9385}
9386
9387void ImGui::Indent(float indent_w)
9388{
9389 ImGuiContext& g = *GImGui;
9390 ImGuiWindow* window = GetCurrentWindow();
9391 window->DC.Indent.x += (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing;
9392 window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x;
9393}
9394
9395void ImGui::Unindent(float indent_w)
9396{
9397 ImGuiContext& g = *GImGui;
9398 ImGuiWindow* window = GetCurrentWindow();
9399 window->DC.Indent.x -= (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing;
9400 window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x;
9401}
9402
9403// Affect large frame+labels widgets only.
9404void ImGui::SetNextItemWidth(float item_width)
9405{
9406 ImGuiContext& g = *GImGui;
9408 g.NextItemData.Width = item_width;
9409}
9410
9411// FIXME: Remove the == 0.0f behavior?
9412void ImGui::PushItemWidth(float item_width)
9413{
9414 ImGuiContext& g = *GImGui;
9415 ImGuiWindow* window = g.CurrentWindow;
9416 window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); // Backup current width
9417 window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width);
9418 g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth;
9419}
9420
9421void ImGui::PushMultiItemsWidths(int components, float w_full)
9422{
9423 ImGuiContext& g = *GImGui;
9424 ImGuiWindow* window = g.CurrentWindow;
9425 const ImGuiStyle& style = g.Style;
9426 const float w_item_one = ImMax(1.0f, IM_FLOOR((w_full - (style.ItemInnerSpacing.x) * (components - 1)) / (float)components));
9427 const float w_item_last = ImMax(1.0f, IM_FLOOR(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components - 1)));
9428 window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); // Backup current width
9429 window->DC.ItemWidthStack.push_back(w_item_last);
9430 for (int i = 0; i < components - 2; i++)
9431 window->DC.ItemWidthStack.push_back(w_item_one);
9432 window->DC.ItemWidth = (components == 1) ? w_item_last : w_item_one;
9433 g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth;
9434}
9435
9437{
9438 ImGuiWindow* window = GetCurrentWindow();
9439 window->DC.ItemWidth = window->DC.ItemWidthStack.back();
9440 window->DC.ItemWidthStack.pop_back();
9441}
9442
9443// Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth().
9444// The SetNextItemWidth() data is generally cleared/consumed by ItemAdd() or NextItemData.ClearFlags()
9446{
9447 ImGuiContext& g = *GImGui;
9448 ImGuiWindow* window = g.CurrentWindow;
9449 float w;
9451 w = g.NextItemData.Width;
9452 else
9453 w = window->DC.ItemWidth;
9454 if (w < 0.0f)
9455 {
9456 float region_max_x = GetContentRegionMaxAbs().x;
9457 w = ImMax(1.0f, region_max_x - window->DC.CursorPos.x + w);
9458 }
9459 w = IM_FLOOR(w);
9460 return w;
9461}
9462
9463// [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == CalcItemWidth().
9464// Those two functions CalcItemWidth vs CalcItemSize are awkwardly named because they are not fully symmetrical.
9465// Note that only CalcItemWidth() is publicly exposed.
9466// The 4.0f here may be changed to match CalcItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable)
9467ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h)
9468{
9469 ImGuiContext& g = *GImGui;
9470 ImGuiWindow* window = g.CurrentWindow;
9471
9472 ImVec2 region_max;
9473 if (size.x < 0.0f || size.y < 0.0f)
9474 region_max = GetContentRegionMaxAbs();
9475
9476 if (size.x == 0.0f)
9477 size.x = default_w;
9478 else if (size.x < 0.0f)
9479 size.x = ImMax(4.0f, region_max.x - window->DC.CursorPos.x + size.x);
9480
9481 if (size.y == 0.0f)
9482 size.y = default_h;
9483 else if (size.y < 0.0f)
9484 size.y = ImMax(4.0f, region_max.y - window->DC.CursorPos.y + size.y);
9485
9486 return size;
9487}
9488
9490{
9491 ImGuiContext& g = *GImGui;
9492 return g.FontSize;
9493}
9494
9496{
9497 ImGuiContext& g = *GImGui;
9498 return g.FontSize + g.Style.ItemSpacing.y;
9499}
9500
9502{
9503 ImGuiContext& g = *GImGui;
9504 return g.FontSize + g.Style.FramePadding.y * 2.0f;
9505}
9506
9508{
9509 ImGuiContext& g = *GImGui;
9510 return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y;
9511}
9512
9513// FIXME: All the Contents Region function are messy or misleading. WE WILL AIM TO OBSOLETE ALL OF THEM WITH A NEW "WORK RECT" API. Thanks for your patience!
9514
9515// FIXME: This is in window space (not screen space!).
9517{
9518 ImGuiContext& g = *GImGui;
9519 ImGuiWindow* window = g.CurrentWindow;
9520 ImVec2 mx = window->ContentRegionRect.Max - window->Pos;
9521 if (window->DC.CurrentColumns || g.CurrentTable)
9522 mx.x = window->WorkRect.Max.x - window->Pos.x;
9523 return mx;
9524}
9525
9526// [Internal] Absolute coordinate. Saner. This is not exposed until we finishing refactoring work rect features.
9528{
9529 ImGuiContext& g = *GImGui;
9530 ImGuiWindow* window = g.CurrentWindow;
9531 ImVec2 mx = window->ContentRegionRect.Max;
9532 if (window->DC.CurrentColumns || g.CurrentTable)
9533 mx.x = window->WorkRect.Max.x;
9534 return mx;
9535}
9536
9542
9543// In window space (not screen space!)
9545{
9546 ImGuiWindow* window = GImGui->CurrentWindow;
9547 return window->ContentRegionRect.Min - window->Pos;
9548}
9549
9551{
9552 ImGuiWindow* window = GImGui->CurrentWindow;
9553 return window->ContentRegionRect.Max - window->Pos;
9554}
9555
9556// Lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.)
9557// Groups are currently a mishmash of functionalities which should perhaps be clarified and separated.
9558// FIXME-OPT: Could we safely early out on ->SkipItems?
9560{
9561 ImGuiContext& g = *GImGui;
9562 ImGuiWindow* window = g.CurrentWindow;
9563
9565 ImGuiGroupData& group_data = g.GroupStack.back();
9566 group_data.WindowID = window->ID;
9567 group_data.BackupCursorPos = window->DC.CursorPos;
9568 group_data.BackupCursorMaxPos = window->DC.CursorMaxPos;
9569 group_data.BackupIndent = window->DC.Indent;
9570 group_data.BackupGroupOffset = window->DC.GroupOffset;
9571 group_data.BackupCurrLineSize = window->DC.CurrLineSize;
9574 group_data.BackupHoveredIdIsAlive = g.HoveredId != 0;
9576 group_data.EmitItem = true;
9577
9578 window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x;
9579 window->DC.Indent = window->DC.GroupOffset;
9580 window->DC.CursorMaxPos = window->DC.CursorPos;
9581 window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
9582 if (g.LogEnabled)
9583 g.LogLinePosY = -FLT_MAX; // To enforce a carriage return
9584}
9585
9587{
9588 ImGuiContext& g = *GImGui;
9589 ImGuiWindow* window = g.CurrentWindow;
9590 IM_ASSERT(g.GroupStack.Size > 0); // Mismatched BeginGroup()/EndGroup() calls
9591
9592 ImGuiGroupData& group_data = g.GroupStack.back();
9593 IM_ASSERT(group_data.WindowID == window->ID); // EndGroup() in wrong window?
9594
9595 if (window->DC.IsSetPos)
9597
9598 ImRect group_bb(group_data.BackupCursorPos, ImMax(window->DC.CursorMaxPos, group_data.BackupCursorPos));
9599
9600 window->DC.CursorPos = group_data.BackupCursorPos;
9601 window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos);
9602 window->DC.Indent = group_data.BackupIndent;
9603 window->DC.GroupOffset = group_data.BackupGroupOffset;
9604 window->DC.CurrLineSize = group_data.BackupCurrLineSize;
9606 if (g.LogEnabled)
9607 g.LogLinePosY = -FLT_MAX; // To enforce a carriage return
9608
9609 if (!group_data.EmitItem)
9610 {
9611 g.GroupStack.pop_back();
9612 return;
9613 }
9614
9615 window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now.
9616 ItemSize(group_bb.GetSize());
9617 ItemAdd(group_bb, 0, NULL, ImGuiItemFlags_NoTabStop);
9618
9619 // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group.
9620 // It would be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but would put a little more burden on individual widgets.
9621 // Also if you grep for LastItemId you'll notice it is only used in that context.
9622 // (The two tests not the same because ActiveIdIsAlive is an ID itself, in order to be able to handle ActiveId being overwritten during the frame.)
9623 const bool group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId;
9624 const bool group_contains_prev_active_id = (group_data.BackupActiveIdPreviousFrameIsAlive == false) && (g.ActiveIdPreviousFrameIsAlive == true);
9625 if (group_contains_curr_active_id)
9626 g.LastItemData.ID = g.ActiveId;
9627 else if (group_contains_prev_active_id)
9629 g.LastItemData.Rect = group_bb;
9630
9631 // Forward Hovered flag
9632 const bool group_contains_curr_hovered_id = (group_data.BackupHoveredIdIsAlive == false) && g.HoveredId != 0;
9633 if (group_contains_curr_hovered_id)
9635
9636 // Forward Edited flag
9637 if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame)
9639
9640 // Forward Deactivated flag
9642 if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame)
9644
9645 g.GroupStack.pop_back();
9646 //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug]
9647}
9648
9649
9650//-----------------------------------------------------------------------------
9651// [SECTION] SCROLLING
9652//-----------------------------------------------------------------------------
9653
9654// Helper to snap on edges when aiming at an item very close to the edge,
9655// So the difference between WindowPadding and ItemSpacing will be in the visible area after scrolling.
9656// When we refactor the scrolling API this may be configurable with a flag?
9657// Note that the effect for this won't be visible on X axis with default Style settings as WindowPadding.x == ItemSpacing.x by default.
9658static float CalcScrollEdgeSnap(float target, float snap_min, float snap_max, float snap_threshold, float center_ratio)
9659{
9660 if (target <= snap_min + snap_threshold)
9661 return ImLerp(snap_min, target, center_ratio);
9662 if (target >= snap_max - snap_threshold)
9663 return ImLerp(target, snap_max, center_ratio);
9664 return target;
9665}
9666
9667static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window)
9668{
9669 ImVec2 scroll = window->Scroll;
9670 ImVec2 decoration_size(window->DecoOuterSizeX1 + window->DecoInnerSizeX1 + window->DecoOuterSizeX2, window->DecoOuterSizeY1 + window->DecoInnerSizeY1 + window->DecoOuterSizeY2);
9671 for (int axis = 0; axis < 2; axis++)
9672 {
9673 if (window->ScrollTarget[axis] < FLT_MAX)
9674 {
9675 float center_ratio = window->ScrollTargetCenterRatio[axis];
9676 float scroll_target = window->ScrollTarget[axis];
9677 if (window->ScrollTargetEdgeSnapDist[axis] > 0.0f)
9678 {
9679 float snap_min = 0.0f;
9680 float snap_max = window->ScrollMax[axis] + window->SizeFull[axis] - decoration_size[axis];
9681 scroll_target = CalcScrollEdgeSnap(scroll_target, snap_min, snap_max, window->ScrollTargetEdgeSnapDist[axis], center_ratio);
9682 }
9683 scroll[axis] = scroll_target - center_ratio * (window->SizeFull[axis] - decoration_size[axis]);
9684 }
9685 scroll[axis] = IM_FLOOR(ImMax(scroll[axis], 0.0f));
9686 if (!window->Collapsed && !window->SkipItems)
9687 scroll[axis] = ImMin(scroll[axis], window->ScrollMax[axis]);
9688 }
9689 return scroll;
9690}
9691
9693{
9694 ImGuiContext& g = *GImGui;
9695 ImGuiWindow* window = g.CurrentWindow;
9696 ScrollToRectEx(window, g.LastItemData.NavRect, flags);
9697}
9698
9699void ImGui::ScrollToRect(ImGuiWindow* window, const ImRect& item_rect, ImGuiScrollFlags flags)
9700{
9701 ScrollToRectEx(window, item_rect, flags);
9702}
9703
9704// Scroll to keep newly navigated item fully into view
9706{
9707 ImGuiContext& g = *GImGui;
9708 ImRect scroll_rect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1));
9709 scroll_rect.Min.x = ImMin(scroll_rect.Min.x + window->DecoInnerSizeX1, scroll_rect.Max.x);
9710 scroll_rect.Min.y = ImMin(scroll_rect.Min.y + window->DecoInnerSizeY1, scroll_rect.Max.y);
9711 //GetForegroundDrawList(window)->AddRect(item_rect.Min, item_rect.Max, IM_COL32(255,0,0,255), 0.0f, 0, 5.0f); // [DEBUG]
9712 //GetForegroundDrawList(window)->AddRect(scroll_rect.Min, scroll_rect.Max, IM_COL32_WHITE); // [DEBUG]
9713
9714 // Check that only one behavior is selected per axis
9715 IM_ASSERT((flags & ImGuiScrollFlags_MaskX_) == 0 || ImIsPowerOfTwo(flags & ImGuiScrollFlags_MaskX_));
9716 IM_ASSERT((flags & ImGuiScrollFlags_MaskY_) == 0 || ImIsPowerOfTwo(flags & ImGuiScrollFlags_MaskY_));
9717
9718 // Defaults
9719 ImGuiScrollFlags in_flags = flags;
9720 if ((flags & ImGuiScrollFlags_MaskX_) == 0 && window->ScrollbarX)
9722 if ((flags & ImGuiScrollFlags_MaskY_) == 0)
9724
9725 const bool fully_visible_x = item_rect.Min.x >= scroll_rect.Min.x && item_rect.Max.x <= scroll_rect.Max.x;
9726 const bool fully_visible_y = item_rect.Min.y >= scroll_rect.Min.y && item_rect.Max.y <= scroll_rect.Max.y;
9727 const bool can_be_fully_visible_x = (item_rect.GetWidth() + g.Style.ItemSpacing.x * 2.0f) <= scroll_rect.GetWidth() || (window->AutoFitFramesX > 0) || (window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0;
9728 const bool can_be_fully_visible_y = (item_rect.GetHeight() + g.Style.ItemSpacing.y * 2.0f) <= scroll_rect.GetHeight() || (window->AutoFitFramesY > 0) || (window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0;
9729
9730 if ((flags & ImGuiScrollFlags_KeepVisibleEdgeX) && !fully_visible_x)
9731 {
9732 if (item_rect.Min.x < scroll_rect.Min.x || !can_be_fully_visible_x)
9733 SetScrollFromPosX(window, item_rect.Min.x - g.Style.ItemSpacing.x - window->Pos.x, 0.0f);
9734 else if (item_rect.Max.x >= scroll_rect.Max.x)
9735 SetScrollFromPosX(window, item_rect.Max.x + g.Style.ItemSpacing.x - window->Pos.x, 1.0f);
9736 }
9737 else if (((flags & ImGuiScrollFlags_KeepVisibleCenterX) && !fully_visible_x) || (flags & ImGuiScrollFlags_AlwaysCenterX))
9738 {
9739 if (can_be_fully_visible_x)
9740 SetScrollFromPosX(window, ImFloor((item_rect.Min.x + item_rect.Max.x) * 0.5f) - window->Pos.x, 0.5f);
9741 else
9742 SetScrollFromPosX(window, item_rect.Min.x - window->Pos.x, 0.0f);
9743 }
9744
9745 if ((flags & ImGuiScrollFlags_KeepVisibleEdgeY) && !fully_visible_y)
9746 {
9747 if (item_rect.Min.y < scroll_rect.Min.y || !can_be_fully_visible_y)
9748 SetScrollFromPosY(window, item_rect.Min.y - g.Style.ItemSpacing.y - window->Pos.y, 0.0f);
9749 else if (item_rect.Max.y >= scroll_rect.Max.y)
9750 SetScrollFromPosY(window, item_rect.Max.y + g.Style.ItemSpacing.y - window->Pos.y, 1.0f);
9751 }
9752 else if (((flags & ImGuiScrollFlags_KeepVisibleCenterY) && !fully_visible_y) || (flags & ImGuiScrollFlags_AlwaysCenterY))
9753 {
9754 if (can_be_fully_visible_y)
9755 SetScrollFromPosY(window, ImFloor((item_rect.Min.y + item_rect.Max.y) * 0.5f) - window->Pos.y, 0.5f);
9756 else
9757 SetScrollFromPosY(window, item_rect.Min.y - window->Pos.y, 0.0f);
9758 }
9759
9760 ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window);
9761 ImVec2 delta_scroll = next_scroll - window->Scroll;
9762
9763 // Also scroll parent window to keep us into view if necessary
9765 {
9766 // FIXME-SCROLL: May be an option?
9768 in_flags = (in_flags & ~ImGuiScrollFlags_MaskX_) | ImGuiScrollFlags_KeepVisibleEdgeX;
9771 delta_scroll += ScrollToRectEx(window->ParentWindow, ImRect(item_rect.Min - delta_scroll, item_rect.Max - delta_scroll), in_flags);
9772 }
9773
9774 return delta_scroll;
9775}
9776
9778{
9779 ImGuiWindow* window = GImGui->CurrentWindow;
9780 return window->Scroll.x;
9781}
9782
9784{
9785 ImGuiWindow* window = GImGui->CurrentWindow;
9786 return window->Scroll.y;
9787}
9788
9790{
9791 ImGuiWindow* window = GImGui->CurrentWindow;
9792 return window->ScrollMax.x;
9793}
9794
9796{
9797 ImGuiWindow* window = GImGui->CurrentWindow;
9798 return window->ScrollMax.y;
9799}
9800
9801void ImGui::SetScrollX(ImGuiWindow* window, float scroll_x)
9802{
9803 window->ScrollTarget.x = scroll_x;
9804 window->ScrollTargetCenterRatio.x = 0.0f;
9805 window->ScrollTargetEdgeSnapDist.x = 0.0f;
9806}
9807
9808void ImGui::SetScrollY(ImGuiWindow* window, float scroll_y)
9809{
9810 window->ScrollTarget.y = scroll_y;
9811 window->ScrollTargetCenterRatio.y = 0.0f;
9812 window->ScrollTargetEdgeSnapDist.y = 0.0f;
9813}
9814
9815void ImGui::SetScrollX(float scroll_x)
9816{
9817 ImGuiContext& g = *GImGui;
9818 SetScrollX(g.CurrentWindow, scroll_x);
9819}
9820
9821void ImGui::SetScrollY(float scroll_y)
9822{
9823 ImGuiContext& g = *GImGui;
9824 SetScrollY(g.CurrentWindow, scroll_y);
9825}
9826
9827// Note that a local position will vary depending on initial scroll value,
9828// This is a little bit confusing so bear with us:
9829// - local_pos = (absolution_pos - window->Pos)
9830// - So local_x/local_y are 0.0f for a position at the upper-left corner of a window,
9831// and generally local_x/local_y are >(padding+decoration) && <(size-padding-decoration) when in the visible area.
9832// - They mostly exist because of legacy API.
9833// Following the rules above, when trying to work with scrolling code, consider that:
9834// - SetScrollFromPosY(0.0f) == SetScrollY(0.0f + scroll.y) == has no effect!
9835// - SetScrollFromPosY(-scroll.y) == SetScrollY(-scroll.y + scroll.y) == SetScrollY(0.0f) == reset scroll. Of course writing SetScrollY(0.0f) directly then makes more sense
9836// We store a target position so centering and clamping can occur on the next frame when we are guaranteed to have a known window size
9837void ImGui::SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio)
9838{
9839 IM_ASSERT(center_x_ratio >= 0.0f && center_x_ratio <= 1.0f);
9840 window->ScrollTarget.x = IM_FLOOR(local_x - window->DecoOuterSizeX1 - window->DecoInnerSizeX1 + window->Scroll.x); // Convert local position to scroll offset
9841 window->ScrollTargetCenterRatio.x = center_x_ratio;
9842 window->ScrollTargetEdgeSnapDist.x = 0.0f;
9843}
9844
9845void ImGui::SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio)
9846{
9847 IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f);
9848 window->ScrollTarget.y = IM_FLOOR(local_y - window->DecoOuterSizeY1 - window->DecoInnerSizeY1 + window->Scroll.y); // Convert local position to scroll offset
9849 window->ScrollTargetCenterRatio.y = center_y_ratio;
9850 window->ScrollTargetEdgeSnapDist.y = 0.0f;
9851}
9852
9853void ImGui::SetScrollFromPosX(float local_x, float center_x_ratio)
9854{
9855 ImGuiContext& g = *GImGui;
9856 SetScrollFromPosX(g.CurrentWindow, local_x, center_x_ratio);
9857}
9858
9859void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio)
9860{
9861 ImGuiContext& g = *GImGui;
9862 SetScrollFromPosY(g.CurrentWindow, local_y, center_y_ratio);
9863}
9864
9865// center_x_ratio: 0.0f left of last item, 0.5f horizontal center of last item, 1.0f right of last item.
9866void ImGui::SetScrollHereX(float center_x_ratio)
9867{
9868 ImGuiContext& g = *GImGui;
9869 ImGuiWindow* window = g.CurrentWindow;
9870 float spacing_x = ImMax(window->WindowPadding.x, g.Style.ItemSpacing.x);
9871 float target_pos_x = ImLerp(g.LastItemData.Rect.Min.x - spacing_x, g.LastItemData.Rect.Max.x + spacing_x, center_x_ratio);
9872 SetScrollFromPosX(window, target_pos_x - window->Pos.x, center_x_ratio); // Convert from absolute to local pos
9873
9874 // Tweak: snap on edges when aiming at an item very close to the edge
9875 window->ScrollTargetEdgeSnapDist.x = ImMax(0.0f, window->WindowPadding.x - spacing_x);
9876}
9877
9878// center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item.
9879void ImGui::SetScrollHereY(float center_y_ratio)
9880{
9881 ImGuiContext& g = *GImGui;
9882 ImGuiWindow* window = g.CurrentWindow;
9883 float spacing_y = ImMax(window->WindowPadding.y, g.Style.ItemSpacing.y);
9884 float target_pos_y = ImLerp(window->DC.CursorPosPrevLine.y - spacing_y, window->DC.CursorPosPrevLine.y + window->DC.PrevLineSize.y + spacing_y, center_y_ratio);
9885 SetScrollFromPosY(window, target_pos_y - window->Pos.y, center_y_ratio); // Convert from absolute to local pos
9886
9887 // Tweak: snap on edges when aiming at an item very close to the edge
9888 window->ScrollTargetEdgeSnapDist.y = ImMax(0.0f, window->WindowPadding.y - spacing_y);
9889}
9890
9891//-----------------------------------------------------------------------------
9892// [SECTION] TOOLTIPS
9893//-----------------------------------------------------------------------------
9894
9899
9900bool ImGui::BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags)
9901{
9902 ImGuiContext& g = *GImGui;
9903
9905 {
9906 // The default tooltip position is a little offset to give space to see the context menu (it's also clamped within the current viewport/monitor)
9907 // In the context of a dragging tooltip we try to reduce that offset and we enforce following the cursor.
9908 // Whatever we do we want to call SetNextWindowPos() to enforce a tooltip position and disable clipping the tooltip without our display area, like regular tooltip do.
9909 //ImVec2 tooltip_pos = g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding;
9910 ImVec2 tooltip_pos = g.IO.MousePos + ImVec2(16 * g.Style.MouseCursorScale, 8 * g.Style.MouseCursorScale);
9911 SetNextWindowPos(tooltip_pos);
9913 //PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This would be nice but e.g ColorButton with checkboard has issue with transparent colors :(
9915 }
9916
9917 char window_name[16];
9918 ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", g.TooltipOverrideCount);
9920 if (ImGuiWindow* window = FindWindowByName(window_name))
9921 if (window->Active)
9922 {
9923 // Hide previous tooltip from being displayed. We can't easily "reset" the content of a window so we create a new one.
9925 ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount);
9926 }
9928 Begin(window_name, NULL, flags | extra_window_flags);
9929 // 2023-03-09: Added bool return value to the API, but currently always returning true.
9930 // If this ever returns false we need to update BeginDragDropSource() accordingly.
9931 //if (!ret)
9932 // End();
9933 //return ret;
9934 return true;
9935}
9936
9938{
9939 IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip); // Mismatched BeginTooltip()/EndTooltip() calls
9940 End();
9941}
9942
9943void ImGui::SetTooltipV(const char* fmt, va_list args)
9944{
9946 TextV(fmt, args);
9947 EndTooltip();
9948}
9949
9950void ImGui::SetTooltip(const char* fmt, ...)
9951{
9952 va_list args;
9953 va_start(args, fmt);
9954 SetTooltipV(fmt, args);
9955 va_end(args);
9956}
9957
9958//-----------------------------------------------------------------------------
9959// [SECTION] POPUPS
9960//-----------------------------------------------------------------------------
9961
9962// Supported flags: ImGuiPopupFlags_AnyPopupId, ImGuiPopupFlags_AnyPopupLevel
9964{
9965 ImGuiContext& g = *GImGui;
9966 if (popup_flags & ImGuiPopupFlags_AnyPopupId)
9967 {
9968 // Return true if any popup is open at the current BeginPopup() level of the popup stack
9969 // This may be used to e.g. test for another popups already opened to handle popups priorities at the same level.
9970 IM_ASSERT(id == 0);
9971 if (popup_flags & ImGuiPopupFlags_AnyPopupLevel)
9972 return g.OpenPopupStack.Size > 0;
9973 else
9975 }
9976 else
9977 {
9978 if (popup_flags & ImGuiPopupFlags_AnyPopupLevel)
9979 {
9980 // Return true if the popup is open anywhere in the popup stack
9981 for (int n = 0; n < g.OpenPopupStack.Size; n++)
9982 if (g.OpenPopupStack[n].PopupId == id)
9983 return true;
9984 return false;
9985 }
9986 else
9987 {
9988 // Return true if the popup is open at the current BeginPopup() level of the popup stack (this is the most-common query)
9989 return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == id;
9990 }
9991 }
9992}
9993
9994bool ImGui::IsPopupOpen(const char* str_id, ImGuiPopupFlags popup_flags)
9995{
9996 ImGuiContext& g = *GImGui;
9997 ImGuiID id = (popup_flags & ImGuiPopupFlags_AnyPopupId) ? 0 : g.CurrentWindow->GetID(str_id);
9998 if ((popup_flags & ImGuiPopupFlags_AnyPopupLevel) && id != 0)
9999 IM_ASSERT(0 && "Cannot use IsPopupOpen() with a string id and ImGuiPopupFlags_AnyPopupLevel."); // But non-string version is legal and used internally
10000 return IsPopupOpen(id, popup_flags);
10001}
10002
10004{
10005 ImGuiContext& g = *GImGui;
10006 for (int n = g.OpenPopupStack.Size - 1; n >= 0; n--)
10007 if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window)
10008 if (popup->Flags & ImGuiWindowFlags_Modal)
10009 return popup;
10010 return NULL;
10011}
10012
10014{
10015 ImGuiContext& g = *GImGui;
10016 for (int n = g.OpenPopupStack.Size - 1; n >= 0; n--)
10017 if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window)
10018 if ((popup->Flags & ImGuiWindowFlags_Modal) && IsWindowActiveAndVisible(popup))
10019 return popup;
10020 return NULL;
10021}
10022
10023void ImGui::OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags)
10024{
10025 ImGuiContext& g = *GImGui;
10026 ImGuiID id = g.CurrentWindow->GetID(str_id);
10027 IMGUI_DEBUG_LOG_POPUP("[popup] OpenPopup(\"%s\" -> 0x%08X)\n", str_id, id);
10028 OpenPopupEx(id, popup_flags);
10029}
10030
10032{
10033 OpenPopupEx(id, popup_flags);
10034}
10035
10036// Mark popup as open (toggle toward open state).
10037// Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block.
10038// Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level).
10039// One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL)
10041{
10042 ImGuiContext& g = *GImGui;
10043 ImGuiWindow* parent_window = g.CurrentWindow;
10044 const int current_stack_size = g.BeginPopupStack.Size;
10045
10048 return;
10049
10050 ImGuiPopupData popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack.
10051 popup_ref.PopupId = id;
10052 popup_ref.Window = NULL;
10053 popup_ref.BackupNavWindow = g.NavWindow; // When popup closes focus may be restored to NavWindow (depend on window type).
10054 popup_ref.OpenFrameCount = g.FrameCount;
10055 popup_ref.OpenParentId = parent_window->IDStack.back();
10056 popup_ref.OpenPopupPos = NavCalcPreferredRefPos();
10057 popup_ref.OpenMousePos = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : popup_ref.OpenPopupPos;
10058
10059 IMGUI_DEBUG_LOG_POPUP("[popup] OpenPopupEx(0x%08X)\n", id);
10060 if (g.OpenPopupStack.Size < current_stack_size + 1)
10061 {
10062 g.OpenPopupStack.push_back(popup_ref);
10063 }
10064 else
10065 {
10066 // Gently handle the user mistakenly calling OpenPopup() every frame. It is a programming mistake! However, if we were to run the regular code path, the ui
10067 // would become completely unusable because the popup will always be in hidden-while-calculating-size state _while_ claiming focus. Which would be a very confusing
10068 // situation for the programmer. Instead, we silently allow the popup to proceed, it will keep reappearing and the programming error will be more obvious to understand.
10069 if (g.OpenPopupStack[current_stack_size].PopupId == id && g.OpenPopupStack[current_stack_size].OpenFrameCount == g.FrameCount - 1)
10070 {
10071 g.OpenPopupStack[current_stack_size].OpenFrameCount = popup_ref.OpenFrameCount;
10072 }
10073 else
10074 {
10075 // Close child popups if any, then flag popup for open/reopen
10076 ClosePopupToLevel(current_stack_size, false);
10077 g.OpenPopupStack.push_back(popup_ref);
10078 }
10079
10080 // When reopening a popup we first refocus its parent, otherwise if its parent is itself a popup it would get closed by ClosePopupsOverWindow().
10081 // This is equivalent to what ClosePopupToLevel() does.
10082 //if (g.OpenPopupStack[current_stack_size].PopupId == id)
10083 // FocusWindow(parent_window);
10084 }
10085}
10086
10087// When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it.
10088// This function closes any popups that are over 'ref_window'.
10089void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup)
10090{
10091 ImGuiContext& g = *GImGui;
10092 if (g.OpenPopupStack.Size == 0)
10093 return;
10094
10095 // Don't close our own child popup windows.
10096 int popup_count_to_keep = 0;
10097 if (ref_window)
10098 {
10099 // Find the highest popup which is a descendant of the reference window (generally reference window = NavWindow)
10100 for (; popup_count_to_keep < g.OpenPopupStack.Size; popup_count_to_keep++)
10101 {
10102 ImGuiPopupData& popup = g.OpenPopupStack[popup_count_to_keep];
10103 if (!popup.Window)
10104 continue;
10107 continue;
10108
10109 // Trim the stack unless the popup is a direct parent of the reference window (the reference window is often the NavWindow)
10110 // - With this stack of window, clicking/focusing Popup1 will close Popup2 and Popup3:
10111 // Window -> Popup1 -> Popup2 -> Popup3
10112 // - Each popups may contain child windows, which is why we compare ->RootWindow!
10113 // Window -> Popup1 -> Popup1_Child -> Popup2 -> Popup2_Child
10114 bool ref_window_is_descendent_of_popup = false;
10115 for (int n = popup_count_to_keep; n < g.OpenPopupStack.Size; n++)
10116 if (ImGuiWindow* popup_window = g.OpenPopupStack[n].Window)
10117 if (IsWindowWithinBeginStackOf(ref_window, popup_window))
10118 {
10119 ref_window_is_descendent_of_popup = true;
10120 break;
10121 }
10122 if (!ref_window_is_descendent_of_popup)
10123 break;
10124 }
10125 }
10126 if (popup_count_to_keep < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below
10127 {
10128 IMGUI_DEBUG_LOG_POPUP("[popup] ClosePopupsOverWindow(\"%s\")\n", ref_window ? ref_window->Name : "<NULL>");
10129 ClosePopupToLevel(popup_count_to_keep, restore_focus_to_window_under_popup);
10130 }
10131}
10132
10134{
10135 ImGuiContext& g = *GImGui;
10136
10137 int popup_count_to_keep;
10138 for (popup_count_to_keep = g.OpenPopupStack.Size; popup_count_to_keep > 0; popup_count_to_keep--)
10139 {
10140 ImGuiWindow* window = g.OpenPopupStack[popup_count_to_keep - 1].Window;
10141 if (!window || window->Flags & ImGuiWindowFlags_Modal)
10142 break;
10143 }
10144 if (popup_count_to_keep < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below
10145 ClosePopupToLevel(popup_count_to_keep, true);
10146}
10147
10148void ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup)
10149{
10150 ImGuiContext& g = *GImGui;
10151 IMGUI_DEBUG_LOG_POPUP("[popup] ClosePopupToLevel(%d), restore_focus_to_window_under_popup=%d\n", remaining, restore_focus_to_window_under_popup);
10152 IM_ASSERT(remaining >= 0 && remaining < g.OpenPopupStack.Size);
10153
10154 // Trim open popup stack
10155 ImGuiWindow* popup_window = g.OpenPopupStack[remaining].Window;
10156 ImGuiWindow* popup_backup_nav_window = g.OpenPopupStack[remaining].BackupNavWindow;
10157 g.OpenPopupStack.resize(remaining);
10158
10159 if (restore_focus_to_window_under_popup)
10160 {
10161 ImGuiWindow* focus_window = (popup_window && popup_window->Flags & ImGuiWindowFlags_ChildMenu) ? popup_window->ParentWindow : popup_backup_nav_window;
10162 if (focus_window && !focus_window->WasActive && popup_window)
10163 {
10164 // Fallback
10165 FocusTopMostWindowUnderOne(popup_window, NULL);
10166 }
10167 else
10168 {
10169 if (g.NavLayer == ImGuiNavLayer_Main && focus_window)
10170 focus_window = NavRestoreLastChildNavWindow(focus_window);
10171 FocusWindow(focus_window);
10172 }
10173 }
10174}
10175
10176// Close the popup we have begin-ed into.
10178{
10179 ImGuiContext& g = *GImGui;
10180 int popup_idx = g.BeginPopupStack.Size - 1;
10181 if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.BeginPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId)
10182 return;
10183
10184 // Closing a menu closes its top-most parent popup (unless a modal)
10185 while (popup_idx > 0)
10186 {
10187 ImGuiWindow* popup_window = g.OpenPopupStack[popup_idx].Window;
10188 ImGuiWindow* parent_popup_window = g.OpenPopupStack[popup_idx - 1].Window;
10189 bool close_parent = false;
10190 if (popup_window && (popup_window->Flags & ImGuiWindowFlags_ChildMenu))
10191 if (parent_popup_window && !(parent_popup_window->Flags & ImGuiWindowFlags_MenuBar))
10192 close_parent = true;
10193 if (!close_parent)
10194 break;
10195 popup_idx--;
10196 }
10197 IMGUI_DEBUG_LOG_POPUP("[popup] CloseCurrentPopup %d -> %d\n", g.BeginPopupStack.Size - 1, popup_idx);
10198 ClosePopupToLevel(popup_idx, true);
10199
10200 // A common pattern is to close a popup when selecting a menu item/selectable that will open another window.
10201 // To improve this usage pattern, we avoid nav highlight for a single frame in the parent window.
10202 // Similarly, we could avoid mouse hover highlight in this window but it is less visually problematic.
10203 if (ImGuiWindow* window = g.NavWindow)
10204 window->DC.NavHideHighlightOneFrame = true;
10205}
10206
10207// Attention! BeginPopup() adds default flags which BeginPopupEx()!
10209{
10210 ImGuiContext& g = *GImGui;
10212 {
10213 g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
10214 return false;
10215 }
10216
10217 char name[20];
10218 if (flags & ImGuiWindowFlags_ChildMenu)
10219 ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginMenuCount); // Recycle windows based on depth
10220 else
10221 ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame
10222
10223 flags |= ImGuiWindowFlags_Popup;
10224 bool is_open = Begin(name, NULL, flags);
10225 if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display)
10226 EndPopup();
10227
10228 return is_open;
10229}
10230
10231bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
10232{
10233 ImGuiContext& g = *GImGui;
10234 if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for performance
10235 {
10236 g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
10237 return false;
10238 }
10240 ImGuiID id = g.CurrentWindow->GetID(str_id);
10241 return BeginPopupEx(id, flags);
10242}
10243
10244// If 'p_open' is specified for a modal popup window, the popup will have a regular close button which will close the popup.
10245// Note that popup visibility status is owned by Dear ImGui (and manipulated with e.g. OpenPopup) so the actual value of *p_open is meaningless here.
10246bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags)
10247{
10248 ImGuiContext& g = *GImGui;
10249 ImGuiWindow* window = g.CurrentWindow;
10250 const ImGuiID id = window->GetID(name);
10252 {
10253 g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
10254 return false;
10255 }
10256
10257 // Center modal windows by default for increased visibility
10258 // (this won't really last as settings will kick in, and is mostly for backward compatibility. user may do the same themselves)
10259 // FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window.
10261 {
10262 const ImGuiViewport* viewport = GetMainViewport();
10263 SetNextWindowPos(viewport->GetCenter(), ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f));
10264 }
10265
10267 const bool is_open = Begin(name, p_open, flags);
10268 if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
10269 {
10270 EndPopup();
10271 if (is_open)
10273 return false;
10274 }
10275 return is_open;
10276}
10277
10279{
10280 ImGuiContext& g = *GImGui;
10281 ImGuiWindow* window = g.CurrentWindow;
10282 IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls
10284
10285 // Make all menus and popups wrap around for now, may need to expose that policy (e.g. focus scope could include wrap/loop policy flags used by new move requests)
10286 if (g.NavWindow == window)
10288
10289 // Child-popups don't need to be laid out
10290 IM_ASSERT(g.WithinEndChild == false);
10291 if (window->Flags & ImGuiWindowFlags_ChildWindow)
10292 g.WithinEndChild = true;
10293 End();
10294 g.WithinEndChild = false;
10295}
10296
10297// Helper to open a popup if mouse button is released over the item
10298// - This is essentially the same as BeginPopupContextItem() but without the trailing BeginPopup()
10299void ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiPopupFlags popup_flags)
10300{
10301 ImGuiContext& g = *GImGui;
10302 ImGuiWindow* window = g.CurrentWindow;
10303 int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
10305 {
10306 ImGuiID id = str_id ? window->GetID(str_id) : g.LastItemData.ID; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict!
10307 IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
10308 OpenPopupEx(id, popup_flags);
10309 }
10310}
10311
10312// This is a helper to handle the simplest case of associating one named popup to one given widget.
10313// - To create a popup associated to the last item, you generally want to pass a NULL value to str_id.
10314// - To create a popup with a specific identifier, pass it in str_id.
10315// - This is useful when using using BeginPopupContextItem() on an item which doesn't have an identifier, e.g. a Text() call.
10316// - This is useful when multiple code locations may want to manipulate/open the same popup, given an explicit id.
10317// - You may want to handle the whole on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters).
10318// This is essentially the same as:
10319// id = str_id ? GetID(str_id) : GetItemID();
10320// OpenPopupOnItemClick(str_id, ImGuiPopupFlags_MouseButtonRight);
10321// return BeginPopup(id);
10322// Which is essentially the same as:
10323// id = str_id ? GetID(str_id) : GetItemID();
10324// if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right))
10325// OpenPopup(id);
10326// return BeginPopup(id);
10327// The main difference being that this is tweaked to avoid computing the ID twice.
10328bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flags)
10329{
10330 ImGuiContext& g = *GImGui;
10331 ImGuiWindow* window = g.CurrentWindow;
10332 if (window->SkipItems)
10333 return false;
10334 ImGuiID id = str_id ? window->GetID(str_id) : g.LastItemData.ID; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict!
10335 IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
10336 int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
10338 OpenPopupEx(id, popup_flags);
10340}
10341
10342bool ImGui::BeginPopupContextWindow(const char* str_id, ImGuiPopupFlags popup_flags)
10343{
10344 ImGuiContext& g = *GImGui;
10345 ImGuiWindow* window = g.CurrentWindow;
10346 if (!str_id)
10347 str_id = "window_context";
10348 ImGuiID id = window->GetID(str_id);
10349 int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
10351 if (!(popup_flags & ImGuiPopupFlags_NoOpenOverItems) || !IsAnyItemHovered())
10352 OpenPopupEx(id, popup_flags);
10354}
10355
10356bool ImGui::BeginPopupContextVoid(const char* str_id, ImGuiPopupFlags popup_flags)
10357{
10358 ImGuiContext& g = *GImGui;
10359 ImGuiWindow* window = g.CurrentWindow;
10360 if (!str_id)
10361 str_id = "void_context";
10362 ImGuiID id = window->GetID(str_id);
10363 int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
10365 if (GetTopMostPopupModal() == NULL)
10366 OpenPopupEx(id, popup_flags);
10368}
10369
10370// r_avoid = the rectangle to avoid (e.g. for tooltip it is a rectangle around the mouse cursor which we want to avoid. for popups it's a small point around the cursor.)
10371// r_outer = the visible area rectangle, minus safe area padding. If our popup size won't fit because of safe area padding we ignore it.
10372// (r_outer is usually equivalent to the viewport rectangle minus padding, but when multi-viewports are enabled and monitor
10373// information are available, it may represent the entire platform monitor from the frame of reference of the current viewport.
10374// this allows us to have tooltips/popups displayed out of the parent viewport.)
10375ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy)
10376{
10377 ImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size);
10378 //GetForegroundDrawList()->AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255,0,0,255));
10379 //GetForegroundDrawList()->AddRect(r_outer.Min, r_outer.Max, IM_COL32(0,255,0,255));
10380
10381 // Combo Box policy (we want a connecting edge)
10383 {
10385 for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++)
10386 {
10387 const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n];
10388 if (n != -1 && dir == *last_dir) // Already tried this direction?
10389 continue;
10390 ImVec2 pos;
10391 if (dir == ImGuiDir_Down) pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y); // Below, Toward Right (default)
10392 if (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y); // Above, Toward Right
10393 if (dir == ImGuiDir_Left) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y); // Below, Toward Left
10394 if (dir == ImGuiDir_Up) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y); // Above, Toward Left
10395 if (!r_outer.Contains(ImRect(pos, pos + size)))
10396 continue;
10397 *last_dir = dir;
10398 return pos;
10399 }
10400 }
10401
10402 // Tooltip and Default popup policy
10403 // (Always first try the direction we used on the last frame, if any)
10405 {
10407 for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++)
10408 {
10409 const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n];
10410 if (n != -1 && dir == *last_dir) // Already tried this direction?
10411 continue;
10412
10413 const float avail_w = (dir == ImGuiDir_Left ? r_avoid.Min.x : r_outer.Max.x) - (dir == ImGuiDir_Right ? r_avoid.Max.x : r_outer.Min.x);
10414 const float avail_h = (dir == ImGuiDir_Up ? r_avoid.Min.y : r_outer.Max.y) - (dir == ImGuiDir_Down ? r_avoid.Max.y : r_outer.Min.y);
10415
10416 // If there's not enough room on one axis, there's no point in positioning on a side on this axis (e.g. when not enough width, use a top/bottom position to maximize available width)
10417 if (avail_w < size.x && (dir == ImGuiDir_Left || dir == ImGuiDir_Right))
10418 continue;
10419 if (avail_h < size.y && (dir == ImGuiDir_Up || dir == ImGuiDir_Down))
10420 continue;
10421
10422 ImVec2 pos;
10423 pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x;
10424 pos.y = (dir == ImGuiDir_Up) ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down) ? r_avoid.Max.y : base_pos_clamped.y;
10425
10426 // Clamp top-left corner of popup
10427 pos.x = ImMax(pos.x, r_outer.Min.x);
10428 pos.y = ImMax(pos.y, r_outer.Min.y);
10429
10430 *last_dir = dir;
10431 return pos;
10432 }
10433 }
10434
10435 // Fallback when not enough room:
10436 *last_dir = ImGuiDir_None;
10437
10438 // For tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible.
10440 return ref_pos + ImVec2(2, 2);
10441
10442 // Otherwise try to keep within display
10443 ImVec2 pos = ref_pos;
10444 pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x);
10445 pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y);
10446 return pos;
10447}
10448
10449// Note that this is used for popups, which can overlap the non work-area of individual viewports.
10451{
10452 ImGuiContext& g = *GImGui;
10453 IM_UNUSED(window);
10454 ImRect r_screen = ((ImGuiViewportP*)(void*)GetMainViewport())->GetMainRect();
10456 r_screen.Expand(ImVec2((r_screen.GetWidth() > padding.x * 2) ? -padding.x : 0.0f, (r_screen.GetHeight() > padding.y * 2) ? -padding.y : 0.0f));
10457 return r_screen;
10458}
10459
10461{
10462 ImGuiContext& g = *GImGui;
10463
10464 ImRect r_outer = GetPopupAllowedExtentRect(window);
10465 if (window->Flags & ImGuiWindowFlags_ChildMenu)
10466 {
10467 // Child menus typically request _any_ position within the parent menu item, and then we move the new menu outside the parent bounds.
10468 // This is how we end up with child menus appearing (most-commonly) on the right of the parent menu.
10469 IM_ASSERT(g.CurrentWindow == window);
10470 ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.Size - 2].Window;
10471 float horizontal_overlap = g.Style.ItemInnerSpacing.x; // We want some overlap to convey the relative depth of each menu (currently the amount of overlap is hard-coded to style.ItemSpacing.x).
10472 ImRect r_avoid;
10473 if (parent_window->DC.MenuBarAppending)
10474 r_avoid = ImRect(-FLT_MAX, parent_window->ClipRect.Min.y, FLT_MAX, parent_window->ClipRect.Max.y); // Avoid parent menu-bar. If we wanted multi-line menu-bar, we may instead want to have the calling window setup e.g. a NextWindowData.PosConstraintAvoidRect field
10475 else
10476 r_avoid = ImRect(parent_window->Pos.x + horizontal_overlap, -FLT_MAX, parent_window->Pos.x + parent_window->Size.x - horizontal_overlap - parent_window->ScrollbarSizes.x, FLT_MAX);
10477 return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Default);
10478 }
10479 if (window->Flags & ImGuiWindowFlags_Popup)
10480 {
10481 return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, ImRect(window->Pos, window->Pos), ImGuiPopupPositionPolicy_Default); // Ideally we'd disable r_avoid here
10482 }
10483 if (window->Flags & ImGuiWindowFlags_Tooltip)
10484 {
10485 // Position tooltip (always follows mouse)
10486 float sc = g.Style.MouseCursorScale;
10487 ImVec2 ref_pos = NavCalcPreferredRefPos();
10488 ImRect r_avoid;
10490 r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8);
10491 else
10492 r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24 * sc, ref_pos.y + 24 * sc); // FIXME: Hard-coded based on mouse cursor shape expectation. Exact dimension not very important.
10493 return FindBestWindowPosForPopupEx(ref_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Tooltip);
10494 }
10495 IM_ASSERT(0);
10496 return window->Pos;
10497}
10498
10499//-----------------------------------------------------------------------------
10500// [SECTION] KEYBOARD/GAMEPAD NAVIGATION
10501//-----------------------------------------------------------------------------
10502
10503// FIXME-NAV: The existence of SetNavID vs SetFocusID vs FocusWindow() needs to be clarified/reworked.
10504// In our terminology those should be interchangeable, yet right now this is super confusing.
10505// Those two functions are merely a legacy artifact, so at minimum naming should be clarified.
10506
10508{
10509 ImGuiContext& g = *GImGui;
10510 if (g.NavWindow != window)
10511 {
10512 IMGUI_DEBUG_LOG_FOCUS("[focus] SetNavWindow(\"%s\")\n", window ? window->Name : "<NULL>");
10513 g.NavWindow = window;
10514 }
10516 NavUpdateAnyRequestFlag();
10517}
10518
10519void ImGui::SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel)
10520{
10521 ImGuiContext& g = *GImGui;
10522 IM_ASSERT(g.NavWindow != NULL);
10523 IM_ASSERT(nav_layer == ImGuiNavLayer_Main || nav_layer == ImGuiNavLayer_Menu);
10524 g.NavId = id;
10525 g.NavLayer = nav_layer;
10526 g.NavFocusScopeId = focus_scope_id;
10527 g.NavWindow->NavLastIds[nav_layer] = id;
10528 g.NavWindow->NavRectRel[nav_layer] = rect_rel;
10529}
10530
10532{
10533 ImGuiContext& g = *GImGui;
10534 IM_ASSERT(id != 0);
10535
10536 if (g.NavWindow != window)
10537 SetNavWindow(window);
10538
10539 // Assume that SetFocusID() is called in the context where its window->DC.NavLayerCurrent and g.CurrentFocusScopeId are valid.
10540 // Note that window may be != g.CurrentWindow (e.g. SetFocusID call in InputTextEx for multi-line text)
10541 const ImGuiNavLayer nav_layer = window->DC.NavLayerCurrent;
10542 g.NavId = id;
10543 g.NavLayer = nav_layer;
10545 window->NavLastIds[nav_layer] = id;
10546 if (g.LastItemData.ID == id)
10547 window->NavRectRel[nav_layer] = WindowRectAbsToRel(window, g.LastItemData.NavRect);
10548
10550 g.NavDisableMouseHover = true;
10551 else
10552 g.NavDisableHighlight = true;
10553}
10554
10556{
10557 if (ImFabs(dx) > ImFabs(dy))
10558 return (dx > 0.0f) ? ImGuiDir_Right : ImGuiDir_Left;
10559 return (dy > 0.0f) ? ImGuiDir_Down : ImGuiDir_Up;
10560}
10561
10562static float inline NavScoreItemDistInterval(float a0, float a1, float b0, float b1)
10563{
10564 if (a1 < b0)
10565 return a1 - b0;
10566 if (b1 < a0)
10567 return a0 - b1;
10568 return 0.0f;
10569}
10570
10571static void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect& r, const ImRect& clip_rect)
10572{
10573 if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right)
10574 {
10575 r.Min.y = ImClamp(r.Min.y, clip_rect.Min.y, clip_rect.Max.y);
10576 r.Max.y = ImClamp(r.Max.y, clip_rect.Min.y, clip_rect.Max.y);
10577 }
10578 else // FIXME: PageUp/PageDown are leaving move_dir == None
10579 {
10580 r.Min.x = ImClamp(r.Min.x, clip_rect.Min.x, clip_rect.Max.x);
10581 r.Max.x = ImClamp(r.Max.x, clip_rect.Min.x, clip_rect.Max.x);
10582 }
10583}
10584
10585// Scoring function for gamepad/keyboard directional navigation. Based on https://gist.github.com/rygorous/6981057
10586static bool ImGui::NavScoreItem(ImGuiNavItemData* result)
10587{
10588 ImGuiContext& g = *GImGui;
10589 ImGuiWindow* window = g.CurrentWindow;
10590 if (g.NavLayer != window->DC.NavLayerCurrent)
10591 return false;
10592
10593 // FIXME: Those are not good variables names
10594 ImRect cand = g.LastItemData.NavRect; // Current item nav rectangle
10595 const ImRect curr = g.NavScoringRect; // Current modified source rect (NB: we've applied Max.x = Min.x in NavUpdate() to inhibit the effect of having varied item width)
10597
10598 // When entering through a NavFlattened border, we consider child window items as fully clipped for scoring
10599 if (window->ParentWindow == g.NavWindow)
10600 {
10602 if (!window->ClipRect.Overlaps(cand))
10603 return false;
10604 cand.ClipWithFull(window->ClipRect); // This allows the scored item to not overlap other candidates in the parent window
10605 }
10606
10607 // We perform scoring on items bounding box clipped by the current clipping rectangle on the other axis (clipping on our movement axis would give us equal scores for all clipped items)
10608 // For example, this ensures that items in one column are not reached when moving vertically from items in another column.
10609 NavClampRectToVisibleAreaForMoveDir(g.NavMoveClipDir, cand, window->ClipRect);
10610
10611 // Compute distance between boxes
10612 // FIXME-NAV: Introducing biases for vertical navigation, needs to be removed.
10613 float dbx = NavScoreItemDistInterval(cand.Min.x, cand.Max.x, curr.Min.x, curr.Max.x);
10614 float dby = NavScoreItemDistInterval(ImLerp(cand.Min.y, cand.Max.y, 0.2f), ImLerp(cand.Min.y, cand.Max.y, 0.8f), ImLerp(curr.Min.y, curr.Max.y, 0.2f), ImLerp(curr.Min.y, curr.Max.y, 0.8f)); // Scale down on Y to keep using box-distance for vertically touching items
10615 if (dby != 0.0f && dbx != 0.0f)
10616 dbx = (dbx / 1000.0f) + ((dbx > 0.0f) ? +1.0f : -1.0f);
10617 float dist_box = ImFabs(dbx) + ImFabs(dby);
10618
10619 // Compute distance between centers (this is off by a factor of 2, but we only compare center distances with each other so it doesn't matter)
10620 float dcx = (cand.Min.x + cand.Max.x) - (curr.Min.x + curr.Max.x);
10621 float dcy = (cand.Min.y + cand.Max.y) - (curr.Min.y + curr.Max.y);
10622 float dist_center = ImFabs(dcx) + ImFabs(dcy); // L1 metric (need this for our connectedness guarantee)
10623
10624 // Determine which quadrant of 'curr' our candidate item 'cand' lies in based on distance
10625 ImGuiDir quadrant;
10626 float dax = 0.0f, day = 0.0f, dist_axial = 0.0f;
10627 if (dbx != 0.0f || dby != 0.0f)
10628 {
10629 // For non-overlapping boxes, use distance between boxes
10630 dax = dbx;
10631 day = dby;
10632 dist_axial = dist_box;
10633 quadrant = ImGetDirQuadrantFromDelta(dbx, dby);
10634 }
10635 else if (dcx != 0.0f || dcy != 0.0f)
10636 {
10637 // For overlapping boxes with different centers, use distance between centers
10638 dax = dcx;
10639 day = dcy;
10640 dist_axial = dist_center;
10641 quadrant = ImGetDirQuadrantFromDelta(dcx, dcy);
10642 }
10643 else
10644 {
10645 // Degenerate case: two overlapping buttons with same center, break ties arbitrarily (note that LastItemId here is really the _previous_ item order, but it doesn't matter)
10646 quadrant = (g.LastItemData.ID < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right;
10647 }
10648
10649#if IMGUI_DEBUG_NAV_SCORING
10650 char buf[128];
10651 if (IsMouseHoveringRect(cand.Min, cand.Max))
10652 {
10653 ImFormatString(buf, IM_ARRAYSIZE(buf), "dbox (%.2f,%.2f->%.4f)\ndcen (%.2f,%.2f->%.4f)\nd (%.2f,%.2f->%.4f)\nnav %c, quadrant %c", dbx, dby, dist_box, dcx, dcy, dist_center, dax, day, dist_axial, "WENS"[g.NavMoveDir], "WENS"[quadrant]);
10654 ImDrawList* draw_list = GetForegroundDrawList(window);
10655 draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255,200,0,100));
10656 draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255,255,0,200));
10657 draw_list->AddRectFilled(cand.Max - ImVec2(4, 4), cand.Max + CalcTextSize(buf) + ImVec2(4, 4), IM_COL32(40,0,0,150));
10658 draw_list->AddText(cand.Max, ~0U, buf);
10659 }
10660 else if (g.IO.KeyCtrl) // Hold to preview score in matching quadrant. Press C to rotate.
10661 {
10662 if (quadrant == g.NavMoveDir)
10663 {
10664 ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center);
10665 ImDrawList* draw_list = GetForegroundDrawList(window);
10666 draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 200));
10667 draw_list->AddText(cand.Min, IM_COL32(255, 255, 255, 255), buf);
10668 }
10669 }
10670#endif
10671
10672 // Is it in the quadrant we're interested in moving to?
10673 bool new_best = false;
10674 const ImGuiDir move_dir = g.NavMoveDir;
10675 if (quadrant == move_dir)
10676 {
10677 // Does it beat the current best candidate?
10678 if (dist_box < result->DistBox)
10679 {
10680 result->DistBox = dist_box;
10681 result->DistCenter = dist_center;
10682 return true;
10683 }
10684 if (dist_box == result->DistBox)
10685 {
10686 // Try using distance between center points to break ties
10687 if (dist_center < result->DistCenter)
10688 {
10689 result->DistCenter = dist_center;
10690 new_best = true;
10691 }
10692 else if (dist_center == result->DistCenter)
10693 {
10694 // Still tied! we need to be extra-careful to make sure everything gets linked properly. We consistently break ties by symbolically moving "later" items
10695 // (with higher index) to the right/downwards by an infinitesimal amount since we the current "best" button already (so it must have a lower index),
10696 // this is fairly easy. This rule ensures that all buttons with dx==dy==0 will end up being linked in order of appearance along the x axis.
10697 if (((move_dir == ImGuiDir_Up || move_dir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance
10698 new_best = true;
10699 }
10700 }
10701 }
10702
10703 // Axial check: if 'curr' has no link at all in some direction and 'cand' lies roughly in that direction, add a tentative link. This will only be kept if no "real" matches
10704 // are found, so it only augments the graph produced by the above method using extra links. (important, since it doesn't guarantee strong connectedness)
10705 // This is just to avoid buttons having no links in a particular direction when there's a suitable neighbor. you get good graphs without this too.
10706 // 2017/09/29: FIXME: This now currently only enabled inside menu bars, ideally we'd disable it everywhere. Menus in particular need to catch failure. For general navigation it feels awkward.
10707 // Disabling it may lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option?
10708 if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial) // Check axial match
10710 if ((move_dir == ImGuiDir_Left && dax < 0.0f) || (move_dir == ImGuiDir_Right && dax > 0.0f) || (move_dir == ImGuiDir_Up && day < 0.0f) || (move_dir == ImGuiDir_Down && day > 0.0f))
10711 {
10712 result->DistAxial = dist_axial;
10713 new_best = true;
10714 }
10715
10716 return new_best;
10717}
10718
10719static void ImGui::NavApplyItemToResult(ImGuiNavItemData* result)
10720{
10721 ImGuiContext& g = *GImGui;
10722 ImGuiWindow* window = g.CurrentWindow;
10723 result->Window = window;
10724 result->ID = g.LastItemData.ID;
10726 result->InFlags = g.LastItemData.InFlags;
10727 result->RectRel = WindowRectAbsToRel(window, g.LastItemData.NavRect);
10728}
10729
10730// We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above)
10731// This is called after LastItemData is set.
10732static void ImGui::NavProcessItem()
10733{
10734 ImGuiContext& g = *GImGui;
10735 ImGuiWindow* window = g.CurrentWindow;
10736 const ImGuiID id = g.LastItemData.ID;
10737 const ImRect nav_bb = g.LastItemData.NavRect;
10738 const ImGuiItemFlags item_flags = g.LastItemData.InFlags;
10739
10740 // Process Init Request
10741 if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent && (item_flags & ImGuiItemFlags_Disabled) == 0)
10742 {
10743 // Even if 'ImGuiItemFlags_NoNavDefaultFocus' is on (typically collapse/close button) we record the first ResultId so they can be used as a fallback
10744 const bool candidate_for_nav_default_focus = (item_flags & ImGuiItemFlags_NoNavDefaultFocus) == 0;
10745 if (candidate_for_nav_default_focus || g.NavInitResultId == 0)
10746 {
10747 g.NavInitResultId = id;
10748 g.NavInitResultRectRel = WindowRectAbsToRel(window, nav_bb);
10749 }
10750 if (candidate_for_nav_default_focus)
10751 {
10752 g.NavInitRequest = false; // Found a match, clear request
10753 NavUpdateAnyRequestFlag();
10754 }
10755 }
10756
10757 // Process Move Request (scoring for navigation)
10758 // FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRect + scoring from a rect wrapped according to current wrapping policy)
10759 if (g.NavMoveScoringItems && (item_flags & ImGuiItemFlags_Disabled) == 0)
10760 {
10761 const bool is_tabbing = (g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) != 0;
10762 if (is_tabbing)
10763 {
10764 NavProcessItemForTabbingRequest(id, item_flags, g.NavMoveFlags);
10765 }
10766 else if (g.NavId != id || (g.NavMoveFlags & ImGuiNavMoveFlags_AllowCurrentNavId))
10767 {
10768 ImGuiNavItemData* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
10769 if (NavScoreItem(result))
10770 NavApplyItemToResult(result);
10771
10772 // Features like PageUp/PageDown need to maintain a separate score for the visible set of items.
10773 const float VISIBLE_RATIO = 0.70f;
10775 if (ImClamp(nav_bb.Max.y, window->ClipRect.Min.y, window->ClipRect.Max.y) - ImClamp(nav_bb.Min.y, window->ClipRect.Min.y, window->ClipRect.Max.y) >= (nav_bb.Max.y - nav_bb.Min.y) * VISIBLE_RATIO)
10776 if (NavScoreItem(&g.NavMoveResultLocalVisible))
10777 NavApplyItemToResult(&g.NavMoveResultLocalVisible);
10778 }
10779 }
10780
10781 // Update window-relative bounding box of navigated item
10782 if (g.NavId == id)
10783 {
10784 if (g.NavWindow != window)
10785 SetNavWindow(window); // Always refresh g.NavWindow, because some operations such as FocusItem() may not have a window.
10786 g.NavLayer = window->DC.NavLayerCurrent;
10788 g.NavIdIsAlive = true;
10789 window->NavRectRel[window->DC.NavLayerCurrent] = WindowRectAbsToRel(window, nav_bb); // Store item bounding box (relative to window position)
10790 }
10791}
10792
10793// Handle "scoring" of an item for a tabbing/focusing request initiated by NavUpdateCreateTabbingRequest().
10794// Note that SetKeyboardFocusHere() API calls are considered tabbing requests!
10795// - Case 1: no nav/active id: set result to first eligible item, stop storing.
10796// - Case 2: tab forward: on ref id set counter, on counter elapse store result
10797// - Case 3: tab forward wrap: set result to first eligible item (preemptively), on ref id set counter, on next frame if counter hasn't elapsed store result. // FIXME-TABBING: Could be done as a next-frame forwarded request
10798// - Case 4: tab backward: store all results, on ref id pick prev, stop storing
10799// - Case 5: tab backward wrap: store all results, on ref id if no result keep storing until last // FIXME-TABBING: Could be done as next-frame forwarded requested
10800void ImGui::NavProcessItemForTabbingRequest(ImGuiID id, ImGuiItemFlags item_flags, ImGuiNavMoveFlags move_flags)
10801{
10802 ImGuiContext& g = *GImGui;
10803
10804 if ((move_flags & ImGuiNavMoveFlags_FocusApi) == 0)
10806 return;
10807
10808 // - Can always land on an item when using API call.
10809 // - Tabbing with _NavEnableKeyboard (space/enter/arrows): goes through every item.
10810 // - Tabbing without _NavEnableKeyboard: goes through inputable items only.
10811 bool can_stop;
10812 if (move_flags & ImGuiNavMoveFlags_FocusApi)
10813 can_stop = true;
10814 else
10815 can_stop = (item_flags & ImGuiItemFlags_NoTabStop) == 0 && ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) || (item_flags & ImGuiItemFlags_Inputable));
10816
10817 // Always store in NavMoveResultLocal (unlike directional request which uses NavMoveResultOther on sibling/flattened windows)
10819 if (g.NavTabbingDir == +1)
10820 {
10821 // Tab Forward or SetKeyboardFocusHere() with >= 0
10822 if (can_stop && g.NavTabbingResultFirst.ID == 0)
10823 NavApplyItemToResult(&g.NavTabbingResultFirst);
10824 if (can_stop && g.NavTabbingCounter > 0 && --g.NavTabbingCounter == 0)
10826 else if (g.NavId == id)
10827 g.NavTabbingCounter = 1;
10828 }
10829 else if (g.NavTabbingDir == -1)
10830 {
10831 // Tab Backward
10832 if (g.NavId == id)
10833 {
10834 if (result->ID)
10835 {
10836 g.NavMoveScoringItems = false;
10837 NavUpdateAnyRequestFlag();
10838 }
10839 }
10840 else if (can_stop)
10841 {
10842 // Keep applying until reaching NavId
10843 NavApplyItemToResult(result);
10844 }
10845 }
10846 else if (g.NavTabbingDir == 0)
10847 {
10848 if (can_stop && g.NavId == id)
10850 if (can_stop && g.NavTabbingResultFirst.ID == 0) // Tab init
10851 NavApplyItemToResult(&g.NavTabbingResultFirst);
10852 }
10853}
10854
10856{
10857 ImGuiContext& g = *GImGui;
10858 return g.NavMoveScoringItems && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0;
10859}
10860
10861// FIXME: ScoringRect is not set
10862void ImGui::NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags)
10863{
10864 ImGuiContext& g = *GImGui;
10865 IM_ASSERT(g.NavWindow != NULL);
10866
10867 if (move_flags & ImGuiNavMoveFlags_Tabbing)
10869
10871 g.NavMoveDir = move_dir;
10872 g.NavMoveDirForDebug = move_dir;
10873 g.NavMoveClipDir = clip_dir;
10874 g.NavMoveFlags = move_flags;
10875 g.NavMoveScrollFlags = scroll_flags;
10876 g.NavMoveForwardToNextFrame = false;
10881 g.NavTabbingCounter = 0;
10883 NavUpdateAnyRequestFlag();
10884}
10885
10887{
10888 ImGuiContext& g = *GImGui;
10889 g.NavMoveScoringItems = false; // Ensure request doesn't need more processing
10890 NavApplyItemToResult(result);
10891 NavUpdateAnyRequestFlag();
10892}
10893
10895{
10896 ImGuiContext& g = *GImGui;
10898 NavUpdateAnyRequestFlag();
10899}
10900
10901// Forward will reuse the move request again on the next frame (generally with modifications done to it)
10902void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags)
10903{
10904 ImGuiContext& g = *GImGui;
10908 g.NavMoveDir = move_dir;
10909 g.NavMoveClipDir = clip_dir;
10911 g.NavMoveScrollFlags = scroll_flags;
10912}
10913
10914// Navigation wrap-around logic is delayed to the end of the frame because this operation is only valid after entire
10915// popup is assembled and in case of appended popups it is not clear which EndPopup() call is final.
10917{
10918 ImGuiContext& g = *GImGui;
10919 IM_ASSERT(wrap_flags != 0); // Call with _WrapX, _WrapY, _LoopX, _LoopY
10920 // In theory we should test for NavMoveRequestButNoResultYet() but there's no point doing it, NavEndFrame() will do the same test
10921 if (g.NavWindow == window && g.NavMoveScoringItems && g.NavLayer == ImGuiNavLayer_Main)
10922 g.NavMoveFlags |= wrap_flags;
10923}
10924
10925// FIXME: This could be replaced by updating a frame number in each window when (window == NavWindow) and (NavLayer == 0).
10926// This way we could find the last focused window among our children. It would be much less confusing this way?
10927static void ImGui::NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window)
10928{
10929 ImGuiWindow* parent = nav_window;
10930 while (parent && parent->RootWindow != parent && (parent->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
10931 parent = parent->ParentWindow;
10932 if (parent && parent != nav_window)
10933 parent->NavLastChildNavWindow = nav_window;
10934}
10935
10936// Restore the last focused child.
10937// Call when we are expected to land on the Main Layer (0) after FocusWindow()
10938static ImGuiWindow* ImGui::NavRestoreLastChildNavWindow(ImGuiWindow* window)
10939{
10941 return window->NavLastChildNavWindow;
10942 return window;
10943}
10944
10945void ImGui::NavRestoreLayer(ImGuiNavLayer layer)
10946{
10947 ImGuiContext& g = *GImGui;
10948 if (layer == ImGuiNavLayer_Main)
10949 {
10950 ImGuiWindow* prev_nav_window = g.NavWindow;
10951 g.NavWindow = NavRestoreLastChildNavWindow(g.NavWindow); // FIXME-NAV: Should clear ongoing nav requests?
10952 if (prev_nav_window)
10953 IMGUI_DEBUG_LOG_FOCUS("[focus] NavRestoreLayer: from \"%s\" to SetNavWindow(\"%s\")\n", prev_nav_window->Name, g.NavWindow->Name);
10954 }
10955 ImGuiWindow* window = g.NavWindow;
10956 if (window->NavLastIds[layer] != 0)
10957 {
10958 SetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]);
10959 }
10960 else
10961 {
10962 g.NavLayer = layer;
10963 NavInitWindow(window, true);
10964 }
10965}
10966
10967void ImGui::NavRestoreHighlightAfterMove()
10968{
10969 ImGuiContext& g = *GImGui;
10970 g.NavDisableHighlight = false;
10972}
10973
10974static inline void ImGui::NavUpdateAnyRequestFlag()
10975{
10976 ImGuiContext& g = *GImGui;
10978 if (g.NavAnyRequest)
10979 IM_ASSERT(g.NavWindow != NULL);
10980}
10981
10982// This needs to be called before we submit any widget (aka in or before Begin)
10983void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit)
10984{
10985 ImGuiContext& g = *GImGui;
10986 IM_ASSERT(window == g.NavWindow);
10987
10988 if (window->Flags & ImGuiWindowFlags_NoNavInputs)
10989 {
10990 g.NavId = 0;
10992 return;
10993 }
10994
10995 bool init_for_nav = false;
10996 if (window == window->RootWindow || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit)
10997 init_for_nav = true;
10998 IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from NavInitWindow(), init_for_nav=%d, window=\"%s\", layer=%d\n", init_for_nav, window->Name, g.NavLayer);
10999 if (init_for_nav)
11000 {
11001 SetNavID(0, g.NavLayer, window->NavRootFocusScopeId, ImRect());
11002 g.NavInitRequest = true;
11003 g.NavInitRequestFromMove = false;
11004 g.NavInitResultId = 0;
11006 NavUpdateAnyRequestFlag();
11007 }
11008 else
11009 {
11010 g.NavId = window->NavLastIds[0];
11012 }
11013}
11014
11015static ImVec2 ImGui::NavCalcPreferredRefPos()
11016{
11017 ImGuiContext& g = *GImGui;
11018 ImGuiWindow* window = g.NavWindow;
11019 if (g.NavDisableHighlight || !g.NavDisableMouseHover || !window)
11020 {
11021 // Mouse (we need a fallback in case the mouse becomes invalid after being used)
11022 // The +1.0f offset when stored by OpenPopupEx() allows reopening this or another popup (same or another mouse button) while not moving the mouse, it is pretty standard.
11023 // In theory we could move that +1.0f offset in OpenPopupEx()
11024 ImVec2 p = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : g.MouseLastValidPos;
11025 return ImVec2(p.x + 1.0f, p.y);
11026 }
11027 else
11028 {
11029 // When navigation is active and mouse is disabled, pick a position around the bottom left of the currently navigated item
11030 // Take account of upcoming scrolling (maybe set mouse pos should be done in EndFrame?)
11031 ImRect rect_rel = WindowRectRelToAbs(window, window->NavRectRel[g.NavLayer]);
11032 if (window->LastFrameActive != g.FrameCount && (window->ScrollTarget.x != FLT_MAX || window->ScrollTarget.y != FLT_MAX))
11033 {
11034 ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window);
11035 rect_rel.Translate(window->Scroll - next_scroll);
11036 }
11037 ImVec2 pos = ImVec2(rect_rel.Min.x + ImMin(g.Style.FramePadding.x * 4, rect_rel.GetWidth()), rect_rel.Max.y - ImMin(g.Style.FramePadding.y, rect_rel.GetHeight()));
11038 ImGuiViewport* viewport = GetMainViewport();
11039 return ImFloor(ImClamp(pos, viewport->Pos, viewport->Pos + viewport->Size)); // ImFloor() is important because non-integer mouse position application in backend might be lossy and result in undesirable non-zero delta.
11040 }
11041}
11042
11044{
11045 ImGuiContext& g = *GImGui;
11046 float repeat_delay, repeat_rate;
11047 GetTypematicRepeatRate(ImGuiInputFlags_RepeatRateNavTweak, &repeat_delay, &repeat_rate);
11048
11049 ImGuiKey key_less, key_more;
11051 {
11054 }
11055 else
11056 {
11057 key_less = (axis == ImGuiAxis_X) ? ImGuiKey_LeftArrow : ImGuiKey_UpArrow;
11058 key_more = (axis == ImGuiAxis_X) ? ImGuiKey_RightArrow : ImGuiKey_DownArrow;
11059 }
11060 float amount = (float)GetKeyPressedAmount(key_more, repeat_delay, repeat_rate) - (float)GetKeyPressedAmount(key_less, repeat_delay, repeat_rate);
11061 if (amount != 0.0f && IsKeyDown(key_less) && IsKeyDown(key_more)) // Cancel when opposite directions are held, regardless of repeat phase
11062 amount = 0.0f;
11063 return amount;
11064}
11065
11066static void ImGui::NavUpdate()
11067{
11068 ImGuiContext& g = *GImGui;
11069 ImGuiIO& io = g.IO;
11070
11071 io.WantSetMousePos = false;
11072 //if (g.NavScoringDebugCount > 0) IMGUI_DEBUG_LOG_NAV("[nav] NavScoringDebugCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.NavScoringDebugCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest);
11073
11074 // Set input source based on which keys are last pressed (as some features differs when used with Gamepad vs Keyboard)
11075 // FIXME-NAV: Now that keys are separated maybe we can get rid of NavInputSource?
11076 const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
11078 if (nav_gamepad_active)
11079 for (ImGuiKey key : nav_gamepad_keys_to_change_source)
11080 if (IsKeyDown(key))
11081 g.NavInputSource = ImGuiInputSource_Gamepad;
11082 const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
11084 if (nav_keyboard_active)
11085 for (ImGuiKey key : nav_keyboard_keys_to_change_source)
11086 if (IsKeyDown(key))
11087 g.NavInputSource = ImGuiInputSource_Keyboard;
11088
11089 // Process navigation init request (select first/default focus)
11090 if (g.NavInitResultId != 0)
11092 g.NavInitRequest = false;
11093 g.NavInitRequestFromMove = false;
11094 g.NavInitResultId = 0;
11095 g.NavJustMovedToId = 0;
11096
11097 // Process navigation move request
11098 if (g.NavMoveSubmitted)
11100 g.NavTabbingCounter = 0;
11102
11103 // Schedule mouse position update (will be done at the bottom of this function, after 1) processing all move requests and 2) updating scrolling)
11104 bool set_mouse_pos = false;
11105 if (g.NavMousePosDirty && g.NavIdIsAlive)
11107 set_mouse_pos = true;
11108 g.NavMousePosDirty = false;
11110
11111 // Store our return window (for returning from Menu Layer to Main Layer) and clear it as soon as we step back in our own Layer 0
11112 if (g.NavWindow)
11113 NavSaveLastChildNavWindowIntoParent(g.NavWindow);
11116
11117 // Update CTRL+TAB and Windowing features (hold Square to move/resize/etc.)
11118 NavUpdateWindowing();
11119
11120 // Set output flags for user application
11121 io.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs);
11122 io.NavVisible = (io.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL);
11123
11124 // Process NavCancel input (to close a popup, get back to parent, clear focus)
11125 NavUpdateCancelRequest();
11126
11127 // Process manual activation request
11131 {
11132 const bool activate_down = (nav_keyboard_active && IsKeyDown(ImGuiKey_Space)) || (nav_gamepad_active && IsKeyDown(ImGuiKey_NavGamepadActivate));
11133 const bool activate_pressed = activate_down && ((nav_keyboard_active && IsKeyPressed(ImGuiKey_Space, false)) || (nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadActivate, false)));
11134 const bool input_down = (nav_keyboard_active && IsKeyDown(ImGuiKey_Enter)) || (nav_gamepad_active && IsKeyDown(ImGuiKey_NavGamepadInput));
11135 const bool input_pressed = input_down && ((nav_keyboard_active && IsKeyPressed(ImGuiKey_Enter, false)) || (nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadInput, false)));
11136 if (g.ActiveId == 0 && activate_pressed)
11137 {
11138 g.NavActivateId = g.NavId;
11140 }
11141 if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && input_pressed)
11142 {
11143 g.NavActivateId = g.NavId;
11145 }
11146 if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && (activate_down || input_down))
11148 if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && (activate_pressed || input_pressed))
11150 }
11152 g.NavDisableHighlight = true;
11153 if (g.NavActivateId != 0)
11155
11156 // Process programmatic activation request
11157 // FIXME-NAV: Those should eventually be queued (unlike focus they don't cancel each others)
11158 if (g.NavNextActivateId != 0)
11159 {
11162 }
11163 g.NavNextActivateId = 0;
11164
11165 // Process move requests
11166 NavUpdateCreateMoveRequest();
11167 if (g.NavMoveDir == ImGuiDir_None)
11168 NavUpdateCreateTabbingRequest();
11169 NavUpdateAnyRequestFlag();
11170 g.NavIdIsAlive = false;
11171
11172 // Scrolling
11174 {
11175 // *Fallback* manual-scroll with Nav directional keys when window has no navigable item
11176 ImGuiWindow* window = g.NavWindow;
11177 const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * io.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
11178 const ImGuiDir move_dir = g.NavMoveDir;
11179 if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll && move_dir != ImGuiDir_None)
11180 {
11181 if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right)
11182 SetScrollX(window, ImFloor(window->Scroll.x + ((move_dir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));
11183 if (move_dir == ImGuiDir_Up || move_dir == ImGuiDir_Down)
11184 SetScrollY(window, ImFloor(window->Scroll.y + ((move_dir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed));
11185 }
11186
11187 // *Normal* Manual scroll with LStick
11188 // Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds.
11189 if (nav_gamepad_active)
11190 {
11192 const float tweak_factor = IsKeyDown(ImGuiKey_NavGamepadTweakSlow) ? 1.0f / 10.0f : IsKeyDown(ImGuiKey_NavGamepadTweakFast) ? 10.0f : 1.0f;
11193 if (scroll_dir.x != 0.0f && window->ScrollbarX)
11194 SetScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed * tweak_factor));
11195 if (scroll_dir.y != 0.0f)
11196 SetScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed * tweak_factor));
11197 }
11198 }
11199
11200 // Always prioritize mouse highlight if navigation is disabled
11201 if (!nav_keyboard_active && !nav_gamepad_active)
11202 {
11203 g.NavDisableHighlight = true;
11204 g.NavDisableMouseHover = set_mouse_pos = false;
11205 }
11206
11207 // Update mouse position if requested
11208 // (This will take into account the possibility that a Scroll was queued in the window to offset our absolute mouse position before scroll has been applied)
11210 {
11211 io.MousePos = io.MousePosPrev = NavCalcPreferredRefPos();
11212 io.WantSetMousePos = true;
11213 //IMGUI_DEBUG_LOG_IO("SetMousePos: (%.1f,%.1f)\n", io.MousePos.x, io.MousePos.y);
11214 }
11215
11216 // [DEBUG]
11218#if IMGUI_DEBUG_NAV_RECTS
11219 if (g.NavWindow)
11220 {
11222 if (1) { for (int layer = 0; layer < 2; layer++) { ImRect r = WindowRectRelToAbs(g.NavWindow, g.NavWindow->NavRectRel[layer]); draw_list->AddRect(r.Min, r.Max, IM_COL32(255,200,0,255)); } } // [DEBUG]
11223 if (1) { ImU32 col = (!g.NavWindow->Hidden) ? IM_COL32(255,0,255,255) : IM_COL32(255,0,0,255); ImVec2 p = NavCalcPreferredRefPos(); char buf[32]; ImFormatString(buf, 32, "%d", g.NavLayer); draw_list->AddCircleFilled(p, 3.0f, col); draw_list->AddText(NULL, 13.0f, p + ImVec2(8,-4), col, buf); }
11224 }
11225#endif
11226}
11227
11229{
11230 // In very rare cases g.NavWindow may be null (e.g. clearing focus after requesting an init request, which does happen when releasing Alt while clicking on void)
11231 ImGuiContext& g = *GImGui;
11232 if (!g.NavWindow)
11233 return;
11234
11235 // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
11236 // FIXME-NAV: On _NavFlattened windows, g.NavWindow will only be updated during subsequent frame. Not a problem currently.
11237 IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: ApplyResult: NavID 0x%08X in Layer %d Window \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name);
11239 g.NavIdIsAlive = true; // Mark as alive from previous frame as we got a result
11241 NavRestoreHighlightAfterMove();
11242}
11243
11244void ImGui::NavUpdateCreateMoveRequest()
11245{
11246 ImGuiContext& g = *GImGui;
11247 ImGuiIO& io = g.IO;
11248 ImGuiWindow* window = g.NavWindow;
11249 const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
11250 const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
11251
11252 if (g.NavMoveForwardToNextFrame && window != NULL)
11253 {
11254 // Forwarding previous request (which has been modified, e.g. wrap around menus rewrite the requests with a starting rectangle at the other side of the window)
11255 // (preserve most state, which were already set by the NavMoveRequestForward() function)
11258 IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestForward %d\n", g.NavMoveDir);
11259 }
11260 else
11261 {
11262 // Initiate directional inputs request
11266 if (window && !g.NavWindowingTarget && !(window->Flags & ImGuiWindowFlags_NoNavInputs))
11267 {
11269 if (!IsActiveIdUsingNavDir(ImGuiDir_Left) && ((nav_gamepad_active && IsKeyPressed(ImGuiKey_GamepadDpadLeft, ImGuiKeyOwner_None, repeat_mode)) || (nav_keyboard_active && IsKeyPressed(ImGuiKey_LeftArrow, ImGuiKeyOwner_None, repeat_mode)))) { g.NavMoveDir = ImGuiDir_Left; }
11270 if (!IsActiveIdUsingNavDir(ImGuiDir_Right) && ((nav_gamepad_active && IsKeyPressed(ImGuiKey_GamepadDpadRight, ImGuiKeyOwner_None, repeat_mode)) || (nav_keyboard_active && IsKeyPressed(ImGuiKey_RightArrow, ImGuiKeyOwner_None, repeat_mode)))) { g.NavMoveDir = ImGuiDir_Right; }
11271 if (!IsActiveIdUsingNavDir(ImGuiDir_Up) && ((nav_gamepad_active && IsKeyPressed(ImGuiKey_GamepadDpadUp, ImGuiKeyOwner_None, repeat_mode)) || (nav_keyboard_active && IsKeyPressed(ImGuiKey_UpArrow, ImGuiKeyOwner_None, repeat_mode)))) { g.NavMoveDir = ImGuiDir_Up; }
11272 if (!IsActiveIdUsingNavDir(ImGuiDir_Down) && ((nav_gamepad_active && IsKeyPressed(ImGuiKey_GamepadDpadDown, ImGuiKeyOwner_None, repeat_mode)) || (nav_keyboard_active && IsKeyPressed(ImGuiKey_DownArrow, ImGuiKeyOwner_None, repeat_mode)))) { g.NavMoveDir = ImGuiDir_Down; }
11273 }
11275 g.NavScoringNoClipRect = ImRect(+FLT_MAX, +FLT_MAX, -FLT_MAX, -FLT_MAX);
11276 }
11277
11278 // Update PageUp/PageDown/Home/End scroll
11279 // FIXME-NAV: Consider enabling those keys even without the master ImGuiConfigFlags_NavEnableKeyboard flag?
11280 float scoring_rect_offset_y = 0.0f;
11281 if (window && g.NavMoveDir == ImGuiDir_None && nav_keyboard_active)
11282 scoring_rect_offset_y = NavUpdatePageUpPageDown();
11283 if (scoring_rect_offset_y != 0.0f)
11284 {
11285 g.NavScoringNoClipRect = window->InnerRect;
11286 g.NavScoringNoClipRect.TranslateY(scoring_rect_offset_y);
11287 }
11288
11289 // [DEBUG] Always send a request
11290#if IMGUI_DEBUG_NAV_SCORING
11291 if (io.KeyCtrl && IsKeyPressed(ImGuiKey_C))
11293 if (io.KeyCtrl && g.NavMoveDir == ImGuiDir_None)
11294 {
11297 }
11298#endif
11299
11300 // Submit
11301 g.NavMoveForwardToNextFrame = false;
11302 if (g.NavMoveDir != ImGuiDir_None)
11304
11305 // Moving with no reference triggers an init request (will be used as a fallback if the direction fails to find a match)
11306 if (g.NavMoveSubmitted && g.NavId == 0)
11307 {
11308 IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", window ? window->Name : "<NULL>", g.NavLayer);
11310 g.NavInitResultId = 0;
11311 g.NavDisableHighlight = false;
11312 }
11313
11314 // When using gamepad, we project the reference nav bounding box into window visible area.
11315 // This is to allow resuming navigation inside the visible area after doing a large amount of scrolling,
11316 // since with gamepad all movements are relative (can't focus a visible object like we can with the mouse).
11317 if (g.NavMoveSubmitted && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main && window != NULL)// && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded))
11318 {
11319 bool clamp_x = (g.NavMoveFlags & (ImGuiNavMoveFlags_LoopX | ImGuiNavMoveFlags_WrapX)) == 0;
11320 bool clamp_y = (g.NavMoveFlags & (ImGuiNavMoveFlags_LoopY | ImGuiNavMoveFlags_WrapY)) == 0;
11321 ImRect inner_rect_rel = WindowRectAbsToRel(window, ImRect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1)));
11322
11323 // Take account of changing scroll to handle triggering a new move request on a scrolling frame. (#6171)
11324 // Otherwise 'inner_rect_rel' would be off on the move result frame.
11325 inner_rect_rel.Translate(CalcNextScrollFromScrollTargetAndClamp(window) - window->Scroll);
11326
11327 if ((clamp_x || clamp_y) && !inner_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
11328 {
11329 IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel for gamepad move\n");
11330 float pad_x = ImMin(inner_rect_rel.GetWidth(), window->CalcFontSize() * 0.5f);
11331 float pad_y = ImMin(inner_rect_rel.GetHeight(), window->CalcFontSize() * 0.5f); // Terrible approximation for the intent of starting navigation from first fully visible item
11332 inner_rect_rel.Min.x = clamp_x ? (inner_rect_rel.Min.x + pad_x) : -FLT_MAX;
11333 inner_rect_rel.Max.x = clamp_x ? (inner_rect_rel.Max.x - pad_x) : +FLT_MAX;
11334 inner_rect_rel.Min.y = clamp_y ? (inner_rect_rel.Min.y + pad_y) : -FLT_MAX;
11335 inner_rect_rel.Max.y = clamp_y ? (inner_rect_rel.Max.y - pad_y) : +FLT_MAX;
11336 window->NavRectRel[g.NavLayer].ClipWithFull(inner_rect_rel);
11337 g.NavId = 0;
11338 }
11339 }
11340
11341 // For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items)
11342 ImRect scoring_rect;
11343 if (window != NULL)
11344 {
11345 ImRect nav_rect_rel = !window->NavRectRel[g.NavLayer].IsInverted() ? window->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0);
11346 scoring_rect = WindowRectRelToAbs(window, nav_rect_rel);
11347 scoring_rect.TranslateY(scoring_rect_offset_y);
11348 scoring_rect.Min.x = ImMin(scoring_rect.Min.x + 1.0f, scoring_rect.Max.x);
11349 scoring_rect.Max.x = scoring_rect.Min.x;
11350 IM_ASSERT(!scoring_rect.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allow us to remove extraneous ImFabs() calls in NavScoreItem().
11351 //GetForegroundDrawList()->AddRect(scoring_rect.Min, scoring_rect.Max, IM_COL32(255,200,0,255)); // [DEBUG]
11352 //if (!g.NavScoringNoClipRect.IsInverted()) { GetForegroundDrawList()->AddRect(g.NavScoringNoClipRect.Min, g.NavScoringNoClipRect.Max, IM_COL32(255, 200, 0, 255)); } // [DEBUG]
11353 }
11354 g.NavScoringRect = scoring_rect;
11355 g.NavScoringNoClipRect.Add(scoring_rect);
11356}
11357
11358void ImGui::NavUpdateCreateTabbingRequest()
11359{
11360 ImGuiContext& g = *GImGui;
11361 ImGuiWindow* window = g.NavWindow;
11363 if (window == NULL || g.NavWindowingTarget != NULL || (window->Flags & ImGuiWindowFlags_NoNavInputs))
11364 return;
11365
11366 const bool tab_pressed = IsKeyPressed(ImGuiKey_Tab, ImGuiKeyOwner_None, ImGuiInputFlags_Repeat) && !g.IO.KeyCtrl && !g.IO.KeyAlt;
11367 if (!tab_pressed)
11368 return;
11369
11370 // Initiate tabbing request
11371 // (this is ALWAYS ENABLED, regardless of ImGuiConfigFlags_NavEnableKeyboard flag!)
11372 // Initially this was designed to use counters and modulo arithmetic, but that could not work with unsubmitted items (list clipper). Instead we use a strategy close to other move requests.
11373 // See NavProcessItemForTabbingRequest() for a description of the various forward/backward tabbing cases with and without wrapping.
11374 const bool nav_keyboard_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
11375 if (nav_keyboard_active)
11376 g.NavTabbingDir = g.IO.KeyShift ? -1 : (g.NavDisableHighlight == true && g.ActiveId == 0) ? 0 : +1;
11377 else
11378 g.NavTabbingDir = g.IO.KeyShift ? -1 : (g.ActiveId == 0) ? 0 : +1;
11380 ImGuiDir clip_dir = (g.NavTabbingDir < 0) ? ImGuiDir_Up : ImGuiDir_Down;
11381 NavMoveRequestSubmit(ImGuiDir_None, clip_dir, ImGuiNavMoveFlags_Tabbing, scroll_flags); // FIXME-NAV: Once we refactor tabbing, add LegacyApi flag to not activate non-inputable.
11382 g.NavTabbingCounter = -1;
11383}
11384
11385// Apply result from previous frame navigation directional move request. Always called from NavUpdate()
11387{
11388 ImGuiContext& g = *GImGui;
11389#if IMGUI_DEBUG_NAV_SCORING
11390 if (g.NavMoveFlags & ImGuiNavMoveFlags_DebugNoResult) // [DEBUG] Scoring all items in NavWindow at all times
11391 return;
11392#endif
11393
11394 // Select which result to use
11396
11397 // Tabbing forward wrap
11398 if ((g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) && result == NULL)
11399 if ((g.NavTabbingCounter == 1 || g.NavTabbingDir == 0) && g.NavTabbingResultFirst.ID)
11400 result = &g.NavTabbingResultFirst;
11401
11402 // In a situation when there are no results but NavId != 0, re-enable the Navigation highlight (because g.NavId is not considered as a possible result)
11403 if (result == NULL)
11404 {
11408 NavRestoreHighlightAfterMove();
11409 return;
11410 }
11411
11412 // PageUp/PageDown behavior first jumps to the bottom/top mostly visible item, _otherwise_ use the result from the previous/next page.
11415 result = &g.NavMoveResultLocalVisible;
11416
11417 // Maybe entering a flattened child from the outside? In this case solve the tie using the regular scoring rules.
11420 result = &g.NavMoveResultOther;
11421 IM_ASSERT(g.NavWindow && result->Window);
11422
11423 // Scroll to keep newly navigated item fully into view.
11425 {
11427 {
11428 // FIXME: Should remove this
11429 float scroll_target = (g.NavMoveDir == ImGuiDir_Up) ? result->Window->ScrollMax.y : 0.0f;
11430 SetScrollY(result->Window, scroll_target);
11431 }
11432 else
11433 {
11434 ImRect rect_abs = WindowRectRelToAbs(result->Window, result->RectRel);
11435 ScrollToRectEx(result->Window, rect_abs, g.NavMoveScrollFlags);
11436 }
11437 }
11438
11439 if (g.NavWindow != result->Window)
11440 {
11441 IMGUI_DEBUG_LOG_FOCUS("[focus] NavMoveRequest: SetNavWindow(\"%s\")\n", result->Window->Name);
11442 g.NavWindow = result->Window;
11443 }
11444 if (g.ActiveId != result->ID)
11445 ClearActiveID();
11446 if (g.NavId != result->ID)
11447 {
11448 // Don't set NavJustMovedToId if just landed on the same spot (which may happen with ImGuiNavMoveFlags_AllowCurrentNavId)
11449 g.NavJustMovedToId = result->ID;
11452 }
11453
11454 // Focus
11455 IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", result->ID, g.NavLayer, g.NavWindow->Name);
11456 SetNavID(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel);
11457
11458 // Tabbing: Activates Inputable or Focus non-Inputable
11460 {
11461 g.NavNextActivateId = result->ID;
11464 }
11465
11466 // Activate
11468 {
11469 g.NavNextActivateId = result->ID;
11471 }
11472
11473 // Enable nav highlight
11475 NavRestoreHighlightAfterMove();
11476}
11477
11478// Process NavCancel input (to close a popup, get back to parent, clear focus)
11479// FIXME: In order to support e.g. Escape to clear a selection we'll need:
11480// - either to store the equivalent of ActiveIdUsingKeyInputMask for a FocusScope and test for it.
11481// - either to move most/all of those tests to the epilogue/end functions of the scope they are dealing with (e.g. exit child window in EndChild()) or in EndFrame(), to allow an earlier intercept
11482static void ImGui::NavUpdateCancelRequest()
11483{
11484 ImGuiContext& g = *GImGui;
11485 const bool nav_gamepad_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (g.IO.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
11486 const bool nav_keyboard_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
11487 if (!(nav_keyboard_active && IsKeyPressed(ImGuiKey_Escape, ImGuiKeyOwner_None)) && !(nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadCancel, ImGuiKeyOwner_None)))
11488 return;
11489
11490 IMGUI_DEBUG_LOG_NAV("[nav] NavUpdateCancelRequest()\n");
11491 if (g.ActiveId != 0)
11492 {
11493 ClearActiveID();
11494 }
11495 else if (g.NavLayer != ImGuiNavLayer_Main)
11496 {
11497 // Leave the "menu" layer
11498 NavRestoreLayer(ImGuiNavLayer_Main);
11499 NavRestoreHighlightAfterMove();
11500 }
11502 {
11503 // Exit child window
11504 ImGuiWindow* child_window = g.NavWindow;
11505 ImGuiWindow* parent_window = g.NavWindow->ParentWindow;
11506 IM_ASSERT(child_window->ChildId != 0);
11507 ImRect child_rect = child_window->Rect();
11508 FocusWindow(parent_window);
11509 SetNavID(child_window->ChildId, ImGuiNavLayer_Main, 0, WindowRectAbsToRel(parent_window, child_rect));
11510 NavRestoreHighlightAfterMove();
11511 }
11513 {
11514 // Close open popup/menu
11516 }
11517 else
11518 {
11519 // Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were
11521 g.NavWindow->NavLastIds[0] = 0;
11522 g.NavId = 0;
11523 }
11524}
11525
11526// Handle PageUp/PageDown/Home/End keys
11527// Called from NavUpdateCreateMoveRequest() which will use our output to create a move request
11528// FIXME-NAV: This doesn't work properly with NavFlattened siblings as we use NavWindow rectangle for reference
11529// FIXME-NAV: how to get Home/End to aim at the beginning/end of a 2D grid?
11530static float ImGui::NavUpdatePageUpPageDown()
11531{
11532 ImGuiContext& g = *GImGui;
11533 ImGuiWindow* window = g.NavWindow;
11534 if ((window->Flags & ImGuiWindowFlags_NoNavInputs) || g.NavWindowingTarget != NULL)
11535 return 0.0f;
11536
11537 const bool page_up_held = IsKeyDown(ImGuiKey_PageUp, ImGuiKeyOwner_None);
11538 const bool page_down_held = IsKeyDown(ImGuiKey_PageDown, ImGuiKeyOwner_None);
11541 if (page_up_held == page_down_held && home_pressed == end_pressed) // Proceed if either (not both) are pressed, otherwise early out
11542 return 0.0f;
11543
11545 NavRestoreLayer(ImGuiNavLayer_Main);
11546
11547 if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll)
11548 {
11549 // Fallback manual-scroll when window has no navigable item
11551 SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight());
11553 SetScrollY(window, window->Scroll.y + window->InnerRect.GetHeight());
11554 else if (home_pressed)
11555 SetScrollY(window, 0.0f);
11556 else if (end_pressed)
11557 SetScrollY(window, window->ScrollMax.y);
11558 }
11559 else
11560 {
11561 ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer];
11562 const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight());
11563 float nav_scoring_rect_offset_y = 0.0f;
11564 if (IsKeyPressed(ImGuiKey_PageUp, true))
11565 {
11566 nav_scoring_rect_offset_y = -page_offset_y;
11567 g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset up, we request the down direction (so we can always land on the last item)
11570 }
11571 else if (IsKeyPressed(ImGuiKey_PageDown, true))
11572 {
11573 nav_scoring_rect_offset_y = +page_offset_y;
11574 g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset down, we request the up direction (so we can always land on the last item)
11577 }
11578 else if (home_pressed)
11579 {
11580 // FIXME-NAV: handling of Home/End is assuming that the top/bottom most item will be visible with Scroll.y == 0/ScrollMax.y
11581 // Scrolling will be handled via the ImGuiNavMoveFlags_ScrollToEdgeY flag, we don't scroll immediately to avoid scrolling happening before nav result.
11582 // Preserve current horizontal position if we have any.
11583 nav_rect_rel.Min.y = nav_rect_rel.Max.y = 0.0f;
11584 if (nav_rect_rel.IsInverted())
11585 nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
11588 // FIXME-NAV: MoveClipDir left to _None, intentional?
11589 }
11590 else if (end_pressed)
11591 {
11592 nav_rect_rel.Min.y = nav_rect_rel.Max.y = window->ContentSize.y;
11593 if (nav_rect_rel.IsInverted())
11594 nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
11597 // FIXME-NAV: MoveClipDir left to _None, intentional?
11598 }
11599 return nav_scoring_rect_offset_y;
11600 }
11601 return 0.0f;
11602}
11603
11604static void ImGui::NavEndFrame()
11605{
11606 ImGuiContext& g = *GImGui;
11607
11608 // Show CTRL+TAB list window
11609 if (g.NavWindowingTarget != NULL)
11610 NavUpdateWindowingOverlay();
11611
11612 // Perform wrap-around in menus
11613 // FIXME-NAV: Wrap may need to apply a weight bias on the other axis. e.g. 4x4 grid with 2 last items missing on last item won't handle LoopY/WrapY correctly.
11614 // FIXME-NAV: Wrap (not Loop) support could be handled by the scoring function and then WrapX would function without an extra frame.
11617 NavUpdateCreateWrappingRequest();
11618}
11619
11620static void ImGui::NavUpdateCreateWrappingRequest()
11621{
11622 ImGuiContext& g = *GImGui;
11623 ImGuiWindow* window = g.NavWindow;
11624
11625 bool do_forward = false;
11626 ImRect bb_rel = window->NavRectRel[g.NavLayer];
11627 ImGuiDir clip_dir = g.NavMoveDir;
11628 const ImGuiNavMoveFlags move_flags = g.NavMoveFlags;
11630 {
11631 bb_rel.Min.x = bb_rel.Max.x = window->ContentSize.x + window->WindowPadding.x;
11632 if (move_flags & ImGuiNavMoveFlags_WrapX)
11633 {
11634 bb_rel.TranslateY(-bb_rel.GetHeight()); // Previous row
11635 clip_dir = ImGuiDir_Up;
11636 }
11637 do_forward = true;
11638 }
11640 {
11641 bb_rel.Min.x = bb_rel.Max.x = -window->WindowPadding.x;
11642 if (move_flags & ImGuiNavMoveFlags_WrapX)
11643 {
11644 bb_rel.TranslateY(+bb_rel.GetHeight()); // Next row
11645 clip_dir = ImGuiDir_Down;
11646 }
11647 do_forward = true;
11648 }
11650 {
11651 bb_rel.Min.y = bb_rel.Max.y = window->ContentSize.y + window->WindowPadding.y;
11652 if (move_flags & ImGuiNavMoveFlags_WrapY)
11653 {
11654 bb_rel.TranslateX(-bb_rel.GetWidth()); // Previous column
11655 clip_dir = ImGuiDir_Left;
11656 }
11657 do_forward = true;
11658 }
11660 {
11661 bb_rel.Min.y = bb_rel.Max.y = -window->WindowPadding.y;
11662 if (move_flags & ImGuiNavMoveFlags_WrapY)
11663 {
11664 bb_rel.TranslateX(+bb_rel.GetWidth()); // Next column
11665 clip_dir = ImGuiDir_Right;
11666 }
11667 do_forward = true;
11668 }
11669 if (!do_forward)
11670 return;
11671 window->NavRectRel[g.NavLayer] = bb_rel;
11672 NavMoveRequestForward(g.NavMoveDir, clip_dir, move_flags, g.NavMoveScrollFlags);
11673}
11674
11675static int ImGui::FindWindowFocusIndex(ImGuiWindow* window)
11676{
11677 ImGuiContext& g = *GImGui;
11678 IM_UNUSED(g);
11679 int order = window->FocusOrder;
11680 IM_ASSERT(window->RootWindow == window); // No child window (not testing _ChildWindow because of docking)
11681 IM_ASSERT(g.WindowsFocusOrder[order] == window);
11682 return order;
11683}
11684
11685static ImGuiWindow* FindWindowNavFocusable(int i_start, int i_stop, int dir) // FIXME-OPT O(N)
11686{
11687 ImGuiContext& g = *GImGui;
11688 for (int i = i_start; i >= 0 && i < g.WindowsFocusOrder.Size && i != i_stop; i += dir)
11690 return g.WindowsFocusOrder[i];
11691 return NULL;
11692}
11693
11694static void NavUpdateWindowingHighlightWindow(int focus_change_dir)
11695{
11696 ImGuiContext& g = *GImGui;
11699 return;
11700
11701 const int i_current = ImGui::FindWindowFocusIndex(g.NavWindowingTarget);
11702 ImGuiWindow* window_target = FindWindowNavFocusable(i_current + focus_change_dir, -INT_MAX, focus_change_dir);
11703 if (!window_target)
11704 window_target = FindWindowNavFocusable((focus_change_dir < 0) ? (g.WindowsFocusOrder.Size - 1) : 0, i_current, focus_change_dir);
11705 if (window_target) // Don't reset windowing target if there's a single window in the list
11706 {
11707 g.NavWindowingTarget = g.NavWindowingTargetAnim = window_target;
11709 }
11710 g.NavWindowingToggleLayer = false;
11711}
11712
11713// Windowing management mode
11714// Keyboard: CTRL+Tab (change focus/move/resize), Alt (toggle menu layer)
11715// Gamepad: Hold Menu/Square (change focus/move/resize), Tap Menu/Square (toggle menu layer)
11716static void ImGui::NavUpdateWindowing()
11717{
11718 ImGuiContext& g = *GImGui;
11719 ImGuiIO& io = g.IO;
11720
11721 ImGuiWindow* apply_focus_window = NULL;
11722 bool apply_toggle_layer = false;
11723
11724 ImGuiWindow* modal_window = GetTopMostPopupModal();
11725 bool allow_windowing = (modal_window == NULL);
11726 if (!allow_windowing)
11727 g.NavWindowingTarget = NULL;
11728
11729 // Fade out
11730 if (g.NavWindowingTargetAnim && g.NavWindowingTarget == NULL)
11731 {
11732 g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha - io.DeltaTime * 10.0f, 0.0f);
11733 if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f)
11734 g.NavWindowingTargetAnim = NULL;
11735 }
11736
11737 // Start CTRL+Tab or Square+L/R window selection
11738 const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
11739 const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
11742 const bool start_windowing_with_gamepad = allow_windowing && nav_gamepad_active && !g.NavWindowingTarget && IsKeyPressed(ImGuiKey_NavGamepadMenu, 0, ImGuiInputFlags_None);
11743 const bool start_windowing_with_keyboard = allow_windowing && !g.NavWindowingTarget && (keyboard_next_window || keyboard_prev_window); // Note: enabled even without NavEnableKeyboard!
11744 if (start_windowing_with_gamepad || start_windowing_with_keyboard)
11745 if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1))
11746 {
11750 g.NavWindowingToggleLayer = start_windowing_with_gamepad ? true : false; // Gamepad starts toggling layer
11751 g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_Keyboard : ImGuiInputSource_Gamepad;
11752 }
11753
11754 // Gamepad update
11757 {
11758 // Highlight only appears after a brief time holding the button, so that a fast tap on PadMenu (to toggle NavLayer) doesn't add visual noise
11759 g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f));
11760
11761 // Select window to focus
11762 const int focus_change_dir = (int)IsKeyPressed(ImGuiKey_GamepadL1) - (int)IsKeyPressed(ImGuiKey_GamepadR1);
11763 if (focus_change_dir != 0)
11764 {
11765 NavUpdateWindowingHighlightWindow(focus_change_dir);
11767 }
11768
11769 // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered top-most)
11771 {
11772 g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore.
11774 apply_toggle_layer = true;
11775 else if (!g.NavWindowingToggleLayer)
11776 apply_focus_window = g.NavWindowingTarget;
11777 g.NavWindowingTarget = NULL;
11778 }
11779 }
11780
11781 // Keyboard: Focus
11783 {
11784 // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise
11786 IM_ASSERT(shared_mods != 0); // Next/Prev shortcut currently needs a shared modifier to "hold", otherwise Prev actions would keep cycling between two windows.
11787 g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // 1.0f
11788 if (keyboard_next_window || keyboard_prev_window)
11789 NavUpdateWindowingHighlightWindow(keyboard_next_window ? -1 : +1);
11790 else if ((io.KeyMods & shared_mods) != shared_mods)
11791 apply_focus_window = g.NavWindowingTarget;
11792 }
11793
11794 // Keyboard: Press and Release ALT to toggle menu layer
11795 // - Testing that only Alt is tested prevents Alt+Shift or AltGR from toggling menu layer.
11796 // - AltGR is normally Alt+Ctrl but we can't reliably detect it (not all backends/systems/layout emit it as Alt+Ctrl). But even on keyboards without AltGR we don't want Alt+Ctrl to open menu anyway.
11797 if (nav_keyboard_active && IsKeyPressed(ImGuiMod_Alt, ImGuiKeyOwner_None))
11798 {
11799 g.NavWindowingToggleLayer = true;
11801 }
11803 {
11804 // We cancel toggling nav layer when any text has been typed (generally while holding Alt). (See #370)
11805 // We cancel toggling nav layer when other modifiers are pressed. (See #4439)
11806 // We cancel toggling nav layer if an owner has claimed the key.
11808 g.NavWindowingToggleLayer = false;
11809
11810 // Apply layer toggle on release
11811 // Important: as before version <18314 we lacked an explicit IO event for focus gain/loss, we also compare mouse validity to detect old backends clearing mouse pos on focus loss.
11813 if (g.ActiveId == 0 || g.ActiveIdAllowOverlap)
11815 apply_toggle_layer = true;
11816 if (!IsKeyDown(ImGuiMod_Alt))
11817 g.NavWindowingToggleLayer = false;
11818 }
11819
11820 // Move window
11822 {
11823 ImVec2 nav_move_dir;
11828 if (nav_move_dir.x != 0.0f || nav_move_dir.y != 0.0f)
11829 {
11830 const float NAV_MOVE_SPEED = 800.0f;
11831 const float move_step = NAV_MOVE_SPEED * io.DeltaTime * ImMin(io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
11832 g.NavWindowingAccumDeltaPos += nav_move_dir * move_step;
11833 g.NavDisableMouseHover = true;
11834 ImVec2 accum_floored = ImFloor(g.NavWindowingAccumDeltaPos);
11835 if (accum_floored.x != 0.0f || accum_floored.y != 0.0f)
11836 {
11837 ImGuiWindow* moving_window = g.NavWindowingTarget->RootWindow;
11838 SetWindowPos(moving_window, moving_window->Pos + accum_floored, ImGuiCond_Always);
11839 g.NavWindowingAccumDeltaPos -= accum_floored;
11840 }
11841 }
11842 }
11843
11844 // Apply final focus
11845 if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindow))
11846 {
11847 ClearActiveID();
11848 NavRestoreHighlightAfterMove();
11849 apply_focus_window = NavRestoreLastChildNavWindow(apply_focus_window);
11850 ClosePopupsOverWindow(apply_focus_window, false);
11851 FocusWindow(apply_focus_window);
11852 if (apply_focus_window->NavLastIds[0] == 0)
11853 NavInitWindow(apply_focus_window, false);
11854
11855 // If the window has ONLY a menu layer (no main layer), select it directly
11856 // Use NavLayersActiveMaskNext since windows didn't have a chance to be Begin()-ed on this frame,
11857 // so CTRL+Tab where the keys are only held for 1 frame will be able to use correct layers mask since
11858 // the target window as already been previewed once.
11859 // FIXME-NAV: This should be done in NavInit.. or in FocusWindow... However in both of those cases,
11860 // we won't have a guarantee that windows has been visible before and therefore NavLayersActiveMask*
11861 // won't be valid.
11862 if (apply_focus_window->DC.NavLayersActiveMaskNext == (1 << ImGuiNavLayer_Menu))
11864 }
11865 if (apply_focus_window)
11866 g.NavWindowingTarget = NULL;
11867
11868 // Apply menu/layer toggle
11869 if (apply_toggle_layer && g.NavWindow)
11870 {
11871 ClearActiveID();
11872
11873 // Move to parent menu if necessary
11874 ImGuiWindow* new_nav_window = g.NavWindow;
11875 while (new_nav_window->ParentWindow
11876 && (new_nav_window->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) == 0
11877 && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0
11878 && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
11879 new_nav_window = new_nav_window->ParentWindow;
11880 if (new_nav_window != g.NavWindow)
11881 {
11882 ImGuiWindow* old_nav_window = g.NavWindow;
11883 FocusWindow(new_nav_window);
11884 new_nav_window->NavLastChildNavWindow = old_nav_window;
11885 }
11886
11887 // Toggle layer
11888 const ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main;
11889 if (new_nav_layer != g.NavLayer)
11890 {
11891 // Reinitialize navigation when entering menu bar with the Alt key (FIXME: could be a properly of the layer?)
11892 if (new_nav_layer == ImGuiNavLayer_Menu)
11893 g.NavWindow->NavLastIds[new_nav_layer] = 0;
11894 NavRestoreLayer(new_nav_layer);
11895 NavRestoreHighlightAfterMove();
11896 }
11897 }
11898}
11899
11900// Window has already passed the IsWindowNavFocusable()
11901static const char* GetFallbackWindowNameForWindowingList(ImGuiWindow* window)
11902{
11903 if (window->Flags & ImGuiWindowFlags_Popup)
11905 if ((window->Flags & ImGuiWindowFlags_MenuBar) && strcmp(window->Name, "##MainMenuBar") == 0)
11908}
11909
11910// Overlay displayed when using CTRL+TAB. Called by EndFrame().
11911void ImGui::NavUpdateWindowingOverlay()
11912{
11913 ImGuiContext& g = *GImGui;
11914 IM_ASSERT(g.NavWindowingTarget != NULL);
11915
11916 if (g.NavWindowingTimer < NAV_WINDOWING_LIST_APPEAR_DELAY)
11917 return;
11918
11919 if (g.NavWindowingListWindow == NULL)
11920 g.NavWindowingListWindow = FindWindowByName("###NavWindowingList");
11921 const ImGuiViewport* viewport = GetMainViewport();
11922 SetNextWindowSizeConstraints(ImVec2(viewport->Size.x * 0.20f, viewport->Size.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX));
11923 SetNextWindowPos(viewport->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
11926 for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--)
11927 {
11928 ImGuiWindow* window = g.WindowsFocusOrder[n];
11929 IM_ASSERT(window != NULL); // Fix static analyzers
11930 if (!IsWindowNavFocusable(window))
11931 continue;
11932 const char* label = window->Name;
11933 if (label == FindRenderedTextEnd(label))
11934 label = GetFallbackWindowNameForWindowingList(window);
11935 Selectable(label, g.NavWindowingTarget == window);
11936 }
11937 End();
11938 PopStyleVar();
11939}
11940
11941
11942//-----------------------------------------------------------------------------
11943// [SECTION] DRAG AND DROP
11944//-----------------------------------------------------------------------------
11945
11947{
11948 ImGuiContext& g = *GImGui;
11949 return g.DragDropActive;
11950}
11951
11965
11966// When this returns true you need to: a) call SetDragDropPayload() exactly once, b) you may render the payload visual/description, c) call EndDragDropSource()
11967// If the item has an identifier:
11968// - This assume/require the item to be activated (typically via ButtonBehavior).
11969// - Therefore if you want to use this with a mouse button other than left mouse button, it is up to the item itself to activate with another button.
11970// - We then pull and use the mouse button that was used to activate the item and use it to carry on the drag.
11971// If the item has no identifier:
11972// - Currently always assume left mouse button.
11974{
11975 ImGuiContext& g = *GImGui;
11976 ImGuiWindow* window = g.CurrentWindow;
11977
11978 // FIXME-DRAGDROP: While in the common-most "drag from non-zero active id" case we can tell the mouse button,
11979 // in both SourceExtern and id==0 cases we may requires something else (explicit flags or some heuristic).
11981
11982 bool source_drag_active = false;
11983 ImGuiID source_id = 0;
11984 ImGuiID source_parent_id = 0;
11985 if (!(flags & ImGuiDragDropFlags_SourceExtern))
11986 {
11987 source_id = g.LastItemData.ID;
11988 if (source_id != 0)
11989 {
11990 // Common path: items with ID
11991 if (g.ActiveId != source_id)
11992 return false;
11993 if (g.ActiveIdMouseButton != -1)
11994 mouse_button = g.ActiveIdMouseButton;
11995 if (g.IO.MouseDown[mouse_button] == false || window->SkipItems)
11996 return false;
11997 g.ActiveIdAllowOverlap = false;
11998 }
11999 else
12000 {
12001 // Uncommon path: items without ID
12002 if (g.IO.MouseDown[mouse_button] == false || window->SkipItems)
12003 return false;
12004 if ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) == 0 && (g.ActiveId == 0 || g.ActiveIdWindow != window))
12005 return false;
12006
12007 // If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to:
12008 // A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag.
12010 {
12011 IM_ASSERT(0);
12012 return false;
12013 }
12014
12015 // Magic fallback to handle items with no assigned ID, e.g. Text(), Image()
12016 // We build a throwaway ID based on current ID stack + relative AABB of items in window.
12017 // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING/RESIZINGG OF THE WIDGET, so if your widget moves your dragging operation will be canceled.
12018 // We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive.
12019 // Rely on keeping other window->LastItemXXX fields intact.
12020 source_id = g.LastItemData.ID = window->GetIDFromRectangle(g.LastItemData.Rect);
12021 KeepAliveID(source_id);
12022 bool is_hovered = ItemHoverable(g.LastItemData.Rect, source_id);
12023 if (is_hovered && g.IO.MouseClicked[mouse_button])
12024 {
12025 SetActiveID(source_id, window);
12026 FocusWindow(window);
12027 }
12028 if (g.ActiveId == source_id) // Allow the underlying widget to display/return hovered during the mouse release frame, else we would get a flicker.
12029 g.ActiveIdAllowOverlap = is_hovered;
12030 }
12031 if (g.ActiveId != source_id)
12032 return false;
12033 source_parent_id = window->IDStack.back();
12034 source_drag_active = IsMouseDragging(mouse_button);
12035
12036 // Disable navigation and key inputs while dragging + cancel existing request if any
12038 }
12039 else
12040 {
12041 window = NULL;
12042 source_id = ImHashStr("#SourceExtern");
12043 source_drag_active = true;
12044 }
12045
12046 if (source_drag_active)
12047 {
12048 if (!g.DragDropActive)
12049 {
12050 IM_ASSERT(source_id != 0);
12051 ClearDragDrop();
12052 ImGuiPayload& payload = g.DragDropPayload;
12053 payload.SourceId = source_id;
12054 payload.SourceParentId = source_parent_id;
12055 g.DragDropActive = true;
12056 g.DragDropSourceFlags = flags;
12057 g.DragDropMouseButton = mouse_button;
12058 if (payload.SourceId == g.ActiveId)
12060 }
12062 g.DragDropWithinSource = true;
12063
12065 {
12066 // Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit)
12067 // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents.
12068 bool ret = BeginTooltip();
12069 IM_ASSERT(ret); // FIXME-NEWBEGIN: If this ever becomes false, we need to Begin("##Hidden", NULL, ImGuiWindowFlags_NoSavedSettings) + SetWindowHiddendAndSkipItemsForCurrentFrame().
12070 IM_UNUSED(ret);
12071
12074 }
12075
12077 g.LastItemData.StatusFlags &= ~ImGuiItemStatusFlags_HoveredRect;
12078
12079 return true;
12080 }
12081 return false;
12082}
12083
12085{
12086 ImGuiContext& g = *GImGui;
12088 IM_ASSERT(g.DragDropWithinSource && "Not after a BeginDragDropSource()?");
12089
12091 EndTooltip();
12092
12093 // Discard the drag if have not called SetDragDropPayload()
12094 if (g.DragDropPayload.DataFrameCount == -1)
12095 ClearDragDrop();
12096 g.DragDropWithinSource = false;
12097}
12098
12099// Use 'cond' to choose to submit payload on drag start or every frame
12100bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond)
12101{
12102 ImGuiContext& g = *GImGui;
12103 ImGuiPayload& payload = g.DragDropPayload;
12104 if (cond == 0)
12105 cond = ImGuiCond_Always;
12106
12107 IM_ASSERT(type != NULL);
12108 IM_ASSERT(strlen(type) < IM_ARRAYSIZE(payload.DataType) && "Payload type can be at most 32 characters long");
12109 IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0));
12110 IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once);
12111 IM_ASSERT(payload.SourceId != 0); // Not called between BeginDragDropSource() and EndDragDropSource()
12112
12113 if (cond == ImGuiCond_Always || payload.DataFrameCount == -1)
12114 {
12115 // Copy payload
12116 ImStrncpy(payload.DataType, type, IM_ARRAYSIZE(payload.DataType));
12118 if (data_size > sizeof(g.DragDropPayloadBufLocal))
12119 {
12120 // Store in heap
12121 g.DragDropPayloadBufHeap.resize((int)data_size);
12122 payload.Data = g.DragDropPayloadBufHeap.Data;
12123 memcpy(payload.Data, data, data_size);
12124 }
12125 else if (data_size > 0)
12126 {
12127 // Store locally
12128 memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));
12129 payload.Data = g.DragDropPayloadBufLocal;
12130 memcpy(payload.Data, data, data_size);
12131 }
12132 else
12133 {
12134 payload.Data = NULL;
12135 }
12136 payload.DataSize = (int)data_size;
12137 }
12138 payload.DataFrameCount = g.FrameCount;
12139
12140 // Return whether the payload has been accepted
12142}
12143
12145{
12146 ImGuiContext& g = *GImGui;
12147 if (!g.DragDropActive)
12148 return false;
12149
12150 ImGuiWindow* window = g.CurrentWindow;
12151 ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow;
12152 if (hovered_window == NULL || window->RootWindow != hovered_window->RootWindow)
12153 return false;
12154 IM_ASSERT(id != 0);
12155 if (!IsMouseHoveringRect(bb.Min, bb.Max) || (id == g.DragDropPayload.SourceId))
12156 return false;
12157 if (window->SkipItems)
12158 return false;
12159
12160 IM_ASSERT(g.DragDropWithinTarget == false);
12161 g.DragDropTargetRect = bb;
12162 g.DragDropTargetId = id;
12163 g.DragDropWithinTarget = true;
12164 return true;
12165}
12166
12167// We don't use BeginDragDropTargetCustom() and duplicate its code because:
12168// 1) we use LastItemRectHoveredRect which handles items that push a temporarily clip rectangle in their code. Calling BeginDragDropTargetCustom(LastItemRect) would not handle them.
12169// 2) and it's faster. as this code may be very frequently called, we want to early out as fast as we can.
12170// Also note how the HoveredWindow test is positioned differently in both functions (in both functions we optimize for the cheapest early out case)
12172{
12173 ImGuiContext& g = *GImGui;
12174 if (!g.DragDropActive)
12175 return false;
12176
12177 ImGuiWindow* window = g.CurrentWindow;
12179 return false;
12180 ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow;
12181 if (hovered_window == NULL || window->RootWindow != hovered_window->RootWindow || window->SkipItems)
12182 return false;
12183
12185 ImGuiID id = g.LastItemData.ID;
12186 if (id == 0)
12187 {
12188 id = window->GetIDFromRectangle(display_rect);
12189 KeepAliveID(id);
12190 }
12191 if (g.DragDropPayload.SourceId == id)
12192 return false;
12193
12194 IM_ASSERT(g.DragDropWithinTarget == false);
12195 g.DragDropTargetRect = display_rect;
12196 g.DragDropTargetId = id;
12197 g.DragDropWithinTarget = true;
12198 return true;
12199}
12200
12202{
12203 ImGuiContext& g = *GImGui;
12204 return g.DragDropActive && g.DragDropAcceptIdPrev != 0;
12205}
12206
12208{
12209 ImGuiContext& g = *GImGui;
12210 ImGuiWindow* window = g.CurrentWindow;
12211 ImGuiPayload& payload = g.DragDropPayload;
12212 IM_ASSERT(g.DragDropActive); // Not called between BeginDragDropTarget() and EndDragDropTarget() ?
12213 IM_ASSERT(payload.DataFrameCount != -1); // Forgot to call EndDragDropTarget() ?
12214 if (type != NULL && !payload.IsDataType(type))
12215 return NULL;
12216
12217 // Accept smallest drag target bounding box, this allows us to nest drag targets conveniently without ordering constraints.
12218 // NB: We currently accept NULL id as target. However, overlapping targets requires a unique ID to function!
12219 const bool was_accepted_previously = (g.DragDropAcceptIdPrev == g.DragDropTargetId);
12221 float r_surface = r.GetWidth() * r.GetHeight();
12222 if (r_surface > g.DragDropAcceptIdCurrRectSurface)
12223 return NULL;
12224
12225 g.DragDropAcceptFlags = flags;
12227 g.DragDropAcceptIdCurrRectSurface = r_surface;
12228 //IMGUI_DEBUG_LOG("AcceptDragDropPayload(): %08X: accept\n", g.DragDropTargetId);
12229
12230 // Render default drop visuals
12231 payload.Preview = was_accepted_previously;
12232 flags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); // Source can also inhibit the preview (useful for external sources that live for 1 frame)
12233 if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview)
12234 window->DrawList->AddRect(r.Min - ImVec2(3.5f,3.5f), r.Max + ImVec2(3.5f, 3.5f), GetColorU32(ImGuiCol_DragDropTarget), 0.0f, 0, 2.0f);
12235
12237 payload.Delivery = was_accepted_previously && !IsMouseDown(g.DragDropMouseButton); // For extern drag sources affecting OS window focus, it's easier to just test !IsMouseDown() instead of IsMouseReleased()
12238 if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery))
12239 return NULL;
12240
12241 //IMGUI_DEBUG_LOG("AcceptDragDropPayload(): %08X: return payload\n", g.DragDropTargetId);
12242 return &payload;
12243}
12244
12245// FIXME-DRAGDROP: Settle on a proper default visuals for drop target.
12247{
12248 GetWindowDrawList()->AddRect(bb.Min - ImVec2(3.5f, 3.5f), bb.Max + ImVec2(3.5f, 3.5f), GetColorU32(ImGuiCol_DragDropTarget), 0.0f, 0, 2.0f);
12249}
12250
12252{
12253 ImGuiContext& g = *GImGui;
12254 return (g.DragDropActive && g.DragDropPayload.DataFrameCount != -1) ? &g.DragDropPayload : NULL;
12255}
12256
12258{
12259 ImGuiContext& g = *GImGui;
12262 g.DragDropWithinTarget = false;
12263
12264 // Clear drag and drop state payload right after delivery
12266 ClearDragDrop();
12267}
12268
12269//-----------------------------------------------------------------------------
12270// [SECTION] LOGGING/CAPTURING
12271//-----------------------------------------------------------------------------
12272// All text output from the interface can be captured into tty/file/clipboard.
12273// By default, tree nodes are automatically opened during logging.
12274//-----------------------------------------------------------------------------
12275
12276// Pass text data straight to log (without being displayed)
12277static inline void LogTextV(ImGuiContext& g, const char* fmt, va_list args)
12278{
12279 if (g.LogFile)
12280 {
12281 g.LogBuffer.Buf.resize(0);
12282 g.LogBuffer.appendfv(fmt, args);
12283 ImFileWrite(g.LogBuffer.c_str(), sizeof(char), (ImU64)g.LogBuffer.size(), g.LogFile);
12284 }
12285 else
12286 {
12287 g.LogBuffer.appendfv(fmt, args);
12288 }
12289}
12290
12291void ImGui::LogText(const char* fmt, ...)
12292{
12293 ImGuiContext& g = *GImGui;
12294 if (!g.LogEnabled)
12295 return;
12296
12297 va_list args;
12298 va_start(args, fmt);
12299 LogTextV(g, fmt, args);
12300 va_end(args);
12301}
12302
12303void ImGui::LogTextV(const char* fmt, va_list args)
12304{
12305 ImGuiContext& g = *GImGui;
12306 if (!g.LogEnabled)
12307 return;
12308
12309 LogTextV(g, fmt, args);
12310}
12311
12312// Internal version that takes a position to decide on newline placement and pad items according to their depth.
12313// We split text into individual lines to add current tree level padding
12314// FIXME: This code is a little complicated perhaps, considering simplifying the whole system.
12315void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end)
12316{
12317 ImGuiContext& g = *GImGui;
12318 ImGuiWindow* window = g.CurrentWindow;
12319
12320 const char* prefix = g.LogNextPrefix;
12321 const char* suffix = g.LogNextSuffix;
12322 g.LogNextPrefix = g.LogNextSuffix = NULL;
12323
12324 if (!text_end)
12325 text_end = FindRenderedTextEnd(text, text_end);
12326
12327 const bool log_new_line = ref_pos && (ref_pos->y > g.LogLinePosY + g.Style.FramePadding.y + 1);
12328 if (ref_pos)
12329 g.LogLinePosY = ref_pos->y;
12330 if (log_new_line)
12331 {
12333 g.LogLineFirstItem = true;
12334 }
12335
12336 if (prefix)
12337 LogRenderedText(ref_pos, prefix, prefix + strlen(prefix)); // Calculate end ourself to ensure "##" are included here.
12338
12339 // Re-adjust padding if we have popped out of our starting depth
12340 if (g.LogDepthRef > window->DC.TreeDepth)
12341 g.LogDepthRef = window->DC.TreeDepth;
12342 const int tree_depth = (window->DC.TreeDepth - g.LogDepthRef);
12343
12344 const char* text_remaining = text;
12345 for (;;)
12346 {
12347 // Split the string. Each new line (after a '\n') is followed by indentation corresponding to the current depth of our log entry.
12348 // We don't add a trailing \n yet to allow a subsequent item on the same line to be captured.
12349 const char* line_start = text_remaining;
12350 const char* line_end = ImStreolRange(line_start, text_end);
12351 const bool is_last_line = (line_end == text_end);
12352 if (line_start != line_end || !is_last_line)
12353 {
12354 const int line_length = (int)(line_end - line_start);
12355 const int indentation = g.LogLineFirstItem ? tree_depth * 4 : 1;
12356 LogText("%*s%.*s", indentation, "", line_length, line_start);
12357 g.LogLineFirstItem = false;
12358 if (*line_end == '\n')
12359 {
12361 g.LogLineFirstItem = true;
12362 }
12363 }
12364 if (is_last_line)
12365 break;
12366 text_remaining = line_end + 1;
12367 }
12368
12369 if (suffix)
12370 LogRenderedText(ref_pos, suffix, suffix + strlen(suffix));
12371}
12372
12373// Start logging/capturing text output
12374void ImGui::LogBegin(ImGuiLogType type, int auto_open_depth)
12375{
12376 ImGuiContext& g = *GImGui;
12377 ImGuiWindow* window = g.CurrentWindow;
12378 IM_ASSERT(g.LogEnabled == false);
12379 IM_ASSERT(g.LogFile == NULL);
12381 g.LogEnabled = true;
12382 g.LogType = type;
12383 g.LogNextPrefix = g.LogNextSuffix = NULL;
12384 g.LogDepthRef = window->DC.TreeDepth;
12385 g.LogDepthToExpand = ((auto_open_depth >= 0) ? auto_open_depth : g.LogDepthToExpandDefault);
12386 g.LogLinePosY = FLT_MAX;
12387 g.LogLineFirstItem = true;
12388}
12389
12390// Important: doesn't copy underlying data, use carefully (prefix/suffix must be in scope at the time of the next LogRenderedText)
12391void ImGui::LogSetNextTextDecoration(const char* prefix, const char* suffix)
12392{
12393 ImGuiContext& g = *GImGui;
12394 g.LogNextPrefix = prefix;
12395 g.LogNextSuffix = suffix;
12396}
12397
12398void ImGui::LogToTTY(int auto_open_depth)
12399{
12400 ImGuiContext& g = *GImGui;
12401 if (g.LogEnabled)
12402 return;
12403 IM_UNUSED(auto_open_depth);
12404#ifndef IMGUI_DISABLE_TTY_FUNCTIONS
12405 LogBegin(ImGuiLogType_TTY, auto_open_depth);
12406 g.LogFile = stdout;
12407#endif
12408}
12409
12410// Start logging/capturing text output to given file
12411void ImGui::LogToFile(int auto_open_depth, const char* filename)
12412{
12413 ImGuiContext& g = *GImGui;
12414 if (g.LogEnabled)
12415 return;
12416
12417 // FIXME: We could probably open the file in text mode "at", however note that clipboard/buffer logging will still
12418 // be subject to outputting OS-incompatible carriage return if within strings the user doesn't use IM_NEWLINE.
12419 // By opening the file in binary mode "ab" we have consistent output everywhere.
12420 if (!filename)
12421 filename = g.IO.LogFilename;
12422 if (!filename || !filename[0])
12423 return;
12424 ImFileHandle f = ImFileOpen(filename, "ab");
12425 if (!f)
12426 {
12427 IM_ASSERT(0);
12428 return;
12429 }
12430
12431 LogBegin(ImGuiLogType_File, auto_open_depth);
12432 g.LogFile = f;
12433}
12434
12435// Start logging/capturing text output to clipboard
12436void ImGui::LogToClipboard(int auto_open_depth)
12437{
12438 ImGuiContext& g = *GImGui;
12439 if (g.LogEnabled)
12440 return;
12441 LogBegin(ImGuiLogType_Clipboard, auto_open_depth);
12442}
12443
12444void ImGui::LogToBuffer(int auto_open_depth)
12445{
12446 ImGuiContext& g = *GImGui;
12447 if (g.LogEnabled)
12448 return;
12449 LogBegin(ImGuiLogType_Buffer, auto_open_depth);
12450}
12451
12453{
12454 ImGuiContext& g = *GImGui;
12455 if (!g.LogEnabled)
12456 return;
12457
12459 switch (g.LogType)
12460 {
12461 case ImGuiLogType_TTY:
12462#ifndef IMGUI_DISABLE_TTY_FUNCTIONS
12463 fflush(g.LogFile);
12464#endif
12465 break;
12466 case ImGuiLogType_File:
12468 break;
12470 break;
12472 if (!g.LogBuffer.empty())
12474 break;
12475 case ImGuiLogType_None:
12476 IM_ASSERT(0);
12477 break;
12478 }
12479
12480 g.LogEnabled = false;
12482 g.LogFile = NULL;
12483 g.LogBuffer.clear();
12484}
12485
12486// Helper to display logging buttons
12487// FIXME-OBSOLETE: We should probably obsolete this and let the user have their own helper (this is one of the oldest function alive!)
12489{
12490 ImGuiContext& g = *GImGui;
12491
12492 PushID("LogButtons");
12493#ifndef IMGUI_DISABLE_TTY_FUNCTIONS
12494 const bool log_to_tty = Button("Log To TTY"); SameLine();
12495#else
12496 const bool log_to_tty = false;
12497#endif
12498 const bool log_to_file = Button("Log To File"); SameLine();
12499 const bool log_to_clipboard = Button("Log To Clipboard"); SameLine();
12500 PushTabStop(false);
12501 SetNextItemWidth(80.0f);
12502 SliderInt("Default Depth", &g.LogDepthToExpandDefault, 0, 9, NULL);
12503 PopTabStop();
12504 PopID();
12505
12506 // Start logging at the end of the function so that the buttons don't appear in the log
12507 if (log_to_tty)
12508 LogToTTY();
12509 if (log_to_file)
12510 LogToFile();
12511 if (log_to_clipboard)
12513}
12514
12515
12516//-----------------------------------------------------------------------------
12517// [SECTION] SETTINGS
12518//-----------------------------------------------------------------------------
12519// - UpdateSettings() [Internal]
12520// - MarkIniSettingsDirty() [Internal]
12521// - FindSettingsHandler() [Internal]
12522// - ClearIniSettings() [Internal]
12523// - LoadIniSettingsFromDisk()
12524// - LoadIniSettingsFromMemory()
12525// - SaveIniSettingsToDisk()
12526// - SaveIniSettingsToMemory()
12527//-----------------------------------------------------------------------------
12528// - CreateNewWindowSettings() [Internal]
12529// - FindWindowSettingsByID() [Internal]
12530// - FindWindowSettingsByWindow() [Internal]
12531// - ClearWindowSettings() [Internal]
12532// - WindowSettingsHandler_***() [Internal]
12533//-----------------------------------------------------------------------------
12534
12535// Called by NewFrame()
12536void ImGui::UpdateSettings()
12537{
12538 // Load settings on first frame (if not explicitly loaded manually before)
12539 ImGuiContext& g = *GImGui;
12540 if (!g.SettingsLoaded)
12541 {
12543 if (g.IO.IniFilename)
12544 LoadIniSettingsFromDisk(g.IO.IniFilename);
12545 g.SettingsLoaded = true;
12546 }
12547
12548 // Save settings (with a delay after the last modification, so we don't spam disk too much)
12549 if (g.SettingsDirtyTimer > 0.0f)
12550 {
12552 if (g.SettingsDirtyTimer <= 0.0f)
12553 {
12554 if (g.IO.IniFilename != NULL)
12556 else
12557 g.IO.WantSaveIniSettings = true; // Let user know they can call SaveIniSettingsToMemory(). user will need to clear io.WantSaveIniSettings themselves.
12558 g.SettingsDirtyTimer = 0.0f;
12559 }
12560 }
12561}
12562
12564{
12565 ImGuiContext& g = *GImGui;
12566 if (g.SettingsDirtyTimer <= 0.0f)
12568}
12569
12571{
12572 ImGuiContext& g = *GImGui;
12573 if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings))
12574 if (g.SettingsDirtyTimer <= 0.0f)
12576}
12577
12579{
12580 ImGuiContext& g = *GImGui;
12581 IM_ASSERT(FindSettingsHandler(handler->TypeName) == NULL);
12582 g.SettingsHandlers.push_back(*handler);
12583}
12584
12585void ImGui::RemoveSettingsHandler(const char* type_name)
12586{
12587 ImGuiContext& g = *GImGui;
12588 if (ImGuiSettingsHandler* handler = FindSettingsHandler(type_name))
12589 g.SettingsHandlers.erase(handler);
12590}
12591
12593{
12594 ImGuiContext& g = *GImGui;
12595 const ImGuiID type_hash = ImHashStr(type_name);
12596 for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
12597 if (g.SettingsHandlers[handler_n].TypeHash == type_hash)
12598 return &g.SettingsHandlers[handler_n];
12599 return NULL;
12600}
12601
12602// Clear all settings (windows, tables, docking etc.)
12604{
12605 ImGuiContext& g = *GImGui;
12607 for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
12608 if (g.SettingsHandlers[handler_n].ClearAllFn)
12609 g.SettingsHandlers[handler_n].ClearAllFn(&g, &g.SettingsHandlers[handler_n]);
12610}
12611
12612void ImGui::LoadIniSettingsFromDisk(const char* ini_filename)
12613{
12614 size_t file_data_size = 0;
12615 char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_data_size);
12616 if (!file_data)
12617 return;
12618 if (file_data_size > 0)
12619 LoadIniSettingsFromMemory(file_data, (size_t)file_data_size);
12620 IM_FREE(file_data);
12621}
12622
12623// Zero-tolerance, no error reporting, cheap .ini parsing
12624void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size)
12625{
12626 ImGuiContext& g = *GImGui;
12628 //IM_ASSERT(!g.WithinFrameScope && "Cannot be called between NewFrame() and EndFrame()");
12629 //IM_ASSERT(g.SettingsLoaded == false && g.FrameCount == 0);
12630
12631 // For user convenience, we allow passing a non zero-terminated string (hence the ini_size parameter).
12632 // For our convenience and to make the code simpler, we'll also write zero-terminators within the buffer. So let's create a writable copy..
12633 if (ini_size == 0)
12634 ini_size = strlen(ini_data);
12635 g.SettingsIniData.Buf.resize((int)ini_size + 1);
12636 char* const buf = g.SettingsIniData.Buf.Data;
12637 char* const buf_end = buf + ini_size;
12638 memcpy(buf, ini_data, ini_size);
12639 buf_end[0] = 0;
12640
12641 // Call pre-read handlers
12642 // Some types will clear their data (e.g. dock information) some types will allow merge/override (window)
12643 for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
12644 if (g.SettingsHandlers[handler_n].ReadInitFn)
12645 g.SettingsHandlers[handler_n].ReadInitFn(&g, &g.SettingsHandlers[handler_n]);
12646
12647 void* entry_data = NULL;
12648 ImGuiSettingsHandler* entry_handler = NULL;
12649
12650 char* line_end = NULL;
12651 for (char* line = buf; line < buf_end; line = line_end + 1)
12652 {
12653 // Skip new lines markers, then find end of the line
12654 while (*line == '\n' || *line == '\r')
12655 line++;
12656 line_end = line;
12657 while (line_end < buf_end && *line_end != '\n' && *line_end != '\r')
12658 line_end++;
12659 line_end[0] = 0;
12660 if (line[0] == ';')
12661 continue;
12662 if (line[0] == '[' && line_end > line && line_end[-1] == ']')
12663 {
12664 // Parse "[Type][Name]". Note that 'Name' can itself contains [] characters, which is acceptable with the current format and parsing code.
12665 line_end[-1] = 0;
12666 const char* name_end = line_end - 1;
12667 const char* type_start = line + 1;
12668 char* type_end = (char*)(void*)ImStrchrRange(type_start, name_end, ']');
12669 const char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL;
12670 if (!type_end || !name_start)
12671 continue;
12672 *type_end = 0; // Overwrite first ']'
12673 name_start++; // Skip second '['
12674 entry_handler = FindSettingsHandler(type_start);
12675 entry_data = entry_handler ? entry_handler->ReadOpenFn(&g, entry_handler, name_start) : NULL;
12676 }
12677 else if (entry_handler != NULL && entry_data != NULL)
12678 {
12679 // Let type handler parse the line
12680 entry_handler->ReadLineFn(&g, entry_handler, entry_data, line);
12681 }
12682 }
12683 g.SettingsLoaded = true;
12684
12685 // [DEBUG] Restore untouched copy so it can be browsed in Metrics (not strictly necessary)
12686 memcpy(buf, ini_data, ini_size);
12687
12688 // Call post-read handlers
12689 for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
12690 if (g.SettingsHandlers[handler_n].ApplyAllFn)
12691 g.SettingsHandlers[handler_n].ApplyAllFn(&g, &g.SettingsHandlers[handler_n]);
12692}
12693
12694void ImGui::SaveIniSettingsToDisk(const char* ini_filename)
12695{
12696 ImGuiContext& g = *GImGui;
12697 g.SettingsDirtyTimer = 0.0f;
12698 if (!ini_filename)
12699 return;
12700
12701 size_t ini_data_size = 0;
12702 const char* ini_data = SaveIniSettingsToMemory(&ini_data_size);
12703 ImFileHandle f = ImFileOpen(ini_filename, "wt");
12704 if (!f)
12705 return;
12706 ImFileWrite(ini_data, sizeof(char), ini_data_size, f);
12707 ImFileClose(f);
12708}
12709
12710// Call registered handlers (e.g. SettingsHandlerWindow_WriteAll() + custom handlers) to write their stuff into a text buffer
12711const char* ImGui::SaveIniSettingsToMemory(size_t* out_size)
12712{
12713 ImGuiContext& g = *GImGui;
12714 g.SettingsDirtyTimer = 0.0f;
12717 for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
12718 {
12719 ImGuiSettingsHandler* handler = &g.SettingsHandlers[handler_n];
12720 handler->WriteAllFn(&g, handler, &g.SettingsIniData);
12721 }
12722 if (out_size)
12723 *out_size = (size_t)g.SettingsIniData.size();
12724 return g.SettingsIniData.c_str();
12725}
12726
12728{
12729 ImGuiContext& g = *GImGui;
12730
12731#if !IMGUI_DEBUG_INI_SETTINGS
12732 // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID()
12733 // Preserve the full string when IMGUI_DEBUG_INI_SETTINGS is set to make .ini inspection easier.
12734 if (const char* p = strstr(name, "###"))
12735 name = p;
12736#endif
12737 const size_t name_len = strlen(name);
12738
12739 // Allocate chunk
12740 const size_t chunk_size = sizeof(ImGuiWindowSettings) + name_len + 1;
12741 ImGuiWindowSettings* settings = g.SettingsWindows.alloc_chunk(chunk_size);
12743 settings->ID = ImHashStr(name, name_len);
12744 memcpy(settings->GetName(), name, name_len + 1); // Store with zero terminator
12745
12746 return settings;
12747}
12748
12749// We don't provide a FindWindowSettingsByName() because Docking system doesn't always hold on names.
12750// This is called once per window .ini entry + once per newly instantiated window.
12752{
12753 ImGuiContext& g = *GImGui;
12754 for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
12755 if (settings->ID == id)
12756 return settings;
12757 return NULL;
12758}
12759
12760// This is faster if you are holding on a Window already as we don't need to perform a search.
12762{
12763 ImGuiContext& g = *GImGui;
12764 if (window->SettingsOffset != -1)
12766 return FindWindowSettingsByID(window->ID);
12767}
12768
12769// This will revert window to its initial state, including enabling the ImGuiCond_FirstUseEver/ImGuiCond_Once conditions once more.
12770void ImGui::ClearWindowSettings(const char* name)
12771{
12772 //IMGUI_DEBUG_LOG("ClearWindowSettings('%s')\n", name);
12773 ImGuiWindow* window = FindWindowByName(name);
12774 if (window != NULL)
12775 {
12777 InitOrLoadWindowSettings(window, NULL);
12778 }
12779 if (ImGuiWindowSettings* settings = window ? FindWindowSettingsByWindow(window) : FindWindowSettingsByID(ImHashStr(name)))
12780 settings->WantDelete = true;
12781}
12782
12783static void WindowSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*)
12784{
12785 ImGuiContext& g = *ctx;
12786 for (int i = 0; i != g.Windows.Size; i++)
12787 g.Windows[i]->SettingsOffset = -1;
12789}
12790
12791static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name)
12792{
12793 ImGuiID id = ImHashStr(name);
12795 if (settings)
12796 *settings = ImGuiWindowSettings(); // Clear existing if recycling previous entry
12797 else
12798 settings = ImGui::CreateNewWindowSettings(name);
12799 settings->ID = id;
12800 settings->WantApply = true;
12801 return (void*)settings;
12802}
12803
12804static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line)
12805{
12806 ImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry;
12807 int x, y;
12808 int i;
12809 if (sscanf(line, "Pos=%i,%i", &x, &y) == 2) { settings->Pos = ImVec2ih((short)x, (short)y); }
12810 else if (sscanf(line, "Size=%i,%i", &x, &y) == 2) { settings->Size = ImVec2ih((short)x, (short)y); }
12811 else if (sscanf(line, "Collapsed=%d", &i) == 1) { settings->Collapsed = (i != 0); }
12812}
12813
12814// Apply to existing windows (if any)
12815static void WindowSettingsHandler_ApplyAll(ImGuiContext* ctx, ImGuiSettingsHandler*)
12816{
12817 ImGuiContext& g = *ctx;
12818 for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
12819 if (settings->WantApply)
12820 {
12821 if (ImGuiWindow* window = ImGui::FindWindowByID(settings->ID))
12822 ApplyWindowSettings(window, settings);
12823 settings->WantApply = false;
12824 }
12825}
12826
12827static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf)
12828{
12829 // Gather data from windows that were active during this session
12830 // (if a window wasn't opened in this session we preserve its settings)
12831 ImGuiContext& g = *ctx;
12832 for (int i = 0; i != g.Windows.Size; i++)
12833 {
12834 ImGuiWindow* window = g.Windows[i];
12836 continue;
12837
12839 if (!settings)
12840 {
12841 settings = ImGui::CreateNewWindowSettings(window->Name);
12842 window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings);
12843 }
12844 IM_ASSERT(settings->ID == window->ID);
12845 settings->Pos = ImVec2ih(window->Pos);
12846 settings->Size = ImVec2ih(window->SizeFull);
12847
12848 settings->Collapsed = window->Collapsed;
12849 settings->WantDelete = false;
12850 }
12851
12852 // Write to text buffer
12853 buf->reserve(buf->size() + g.SettingsWindows.size() * 6); // ballpark reserve
12854 for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
12855 {
12856 if (settings->WantDelete)
12857 continue;
12858 const char* settings_name = settings->GetName();
12859 buf->appendf("[%s][%s]\n", handler->TypeName, settings_name);
12860 buf->appendf("Pos=%d,%d\n", settings->Pos.x, settings->Pos.y);
12861 buf->appendf("Size=%d,%d\n", settings->Size.x, settings->Size.y);
12862 buf->appendf("Collapsed=%d\n", settings->Collapsed);
12863 buf->append("\n");
12864 }
12865}
12866
12867
12868//-----------------------------------------------------------------------------
12869// [SECTION] LOCALIZATION
12870//-----------------------------------------------------------------------------
12871
12872void ImGui::LocalizeRegisterEntries(const ImGuiLocEntry* entries, int count)
12873{
12874 ImGuiContext& g = *GImGui;
12875 for (int n = 0; n < count; n++)
12876 g.LocalizationTable[entries[n].Key] = entries[n].Text;
12877}
12878
12879
12880//-----------------------------------------------------------------------------
12881// [SECTION] VIEWPORTS, PLATFORM WINDOWS
12882//-----------------------------------------------------------------------------
12883// - GetMainViewport()
12884// - SetWindowViewport() [Internal]
12885// - UpdateViewportsNewFrame() [Internal]
12886// (this section is more complete in the 'docking' branch)
12887//-----------------------------------------------------------------------------
12888
12890{
12891 ImGuiContext& g = *GImGui;
12892 return g.Viewports[0];
12893}
12894
12896{
12897 window->Viewport = viewport;
12898}
12899
12900// Update viewports and monitor infos
12901static void ImGui::UpdateViewportsNewFrame()
12902{
12903 ImGuiContext& g = *GImGui;
12904 IM_ASSERT(g.Viewports.Size == 1);
12905
12906 // Update main viewport with current platform position.
12907 // FIXME-VIEWPORT: Size is driven by backend/user code for backward-compatibility but we should aim to make this more consistent.
12908 ImGuiViewportP* main_viewport = g.Viewports[0];
12910 main_viewport->Pos = ImVec2(0.0f, 0.0f);
12911 main_viewport->Size = g.IO.DisplaySize;
12912
12913 for (int n = 0; n < g.Viewports.Size; n++)
12914 {
12915 ImGuiViewportP* viewport = g.Viewports[n];
12916
12917 // Lock down space taken by menu bars and status bars, reset the offset for fucntions like BeginMainMenuBar() to alter them again.
12918 viewport->WorkOffsetMin = viewport->BuildWorkOffsetMin;
12919 viewport->WorkOffsetMax = viewport->BuildWorkOffsetMax;
12920 viewport->BuildWorkOffsetMin = viewport->BuildWorkOffsetMax = ImVec2(0.0f, 0.0f);
12921 viewport->UpdateWorkRect();
12922 }
12923}
12924
12925//-----------------------------------------------------------------------------
12926// [SECTION] DOCKING
12927//-----------------------------------------------------------------------------
12928
12929// (this section is filled in the 'docking' branch)
12930
12931
12932//-----------------------------------------------------------------------------
12933// [SECTION] PLATFORM DEPENDENT HELPERS
12934//-----------------------------------------------------------------------------
12935
12936#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS)
12937
12938#ifdef _MSC_VER
12939#pragma comment(lib, "user32")
12940#pragma comment(lib, "kernel32")
12941#endif
12942
12943// Win32 clipboard implementation
12944// We use g.ClipboardHandlerData for temporary storage to ensure it is freed on Shutdown()
12945static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx)
12946{
12947 ImGuiContext& g = *(ImGuiContext*)user_data_ctx;
12949 if (!::OpenClipboard(NULL))
12950 return NULL;
12951 HANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT);
12952 if (wbuf_handle == NULL)
12953 {
12954 ::CloseClipboard();
12955 return NULL;
12956 }
12957 if (const WCHAR* wbuf_global = (const WCHAR*)::GlobalLock(wbuf_handle))
12958 {
12959 int buf_len = ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, NULL, 0, NULL, NULL);
12960 g.ClipboardHandlerData.resize(buf_len);
12961 ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, g.ClipboardHandlerData.Data, buf_len, NULL, NULL);
12962 }
12963 ::GlobalUnlock(wbuf_handle);
12964 ::CloseClipboard();
12965 return g.ClipboardHandlerData.Data;
12966}
12967
12968static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
12969{
12970 if (!::OpenClipboard(NULL))
12971 return;
12972 const int wbuf_length = ::MultiByteToWideChar(CP_UTF8, 0, text, -1, NULL, 0);
12973 HGLOBAL wbuf_handle = ::GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(WCHAR));
12974 if (wbuf_handle == NULL)
12975 {
12976 ::CloseClipboard();
12977 return;
12978 }
12979 WCHAR* wbuf_global = (WCHAR*)::GlobalLock(wbuf_handle);
12980 ::MultiByteToWideChar(CP_UTF8, 0, text, -1, wbuf_global, wbuf_length);
12981 ::GlobalUnlock(wbuf_handle);
12982 ::EmptyClipboard();
12983 if (::SetClipboardData(CF_UNICODETEXT, wbuf_handle) == NULL)
12984 ::GlobalFree(wbuf_handle);
12985 ::CloseClipboard();
12986}
12987
12988#elif defined(__APPLE__) && TARGET_OS_OSX && defined(IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS)
12989
12990#include <Carbon/Carbon.h> // Use old API to avoid need for separate .mm file
12991static PasteboardRef main_clipboard = 0;
12992
12993// OSX clipboard implementation
12994// If you enable this you will need to add '-framework ApplicationServices' to your linker command-line!
12995static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
12996{
12997 if (!main_clipboard)
12998 PasteboardCreate(kPasteboardClipboard, &main_clipboard);
12999 PasteboardClear(main_clipboard);
13000 CFDataRef cf_data = CFDataCreate(kCFAllocatorDefault, (const UInt8*)text, strlen(text));
13001 if (cf_data)
13002 {
13003 PasteboardPutItemFlavor(main_clipboard, (PasteboardItemID)1, CFSTR("public.utf8-plain-text"), cf_data, 0);
13004 CFRelease(cf_data);
13005 }
13006}
13007
13008static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx)
13009{
13010 ImGuiContext& g = *(ImGuiContext*)user_data_ctx;
13011 if (!main_clipboard)
13012 PasteboardCreate(kPasteboardClipboard, &main_clipboard);
13013 PasteboardSynchronize(main_clipboard);
13014
13015 ItemCount item_count = 0;
13016 PasteboardGetItemCount(main_clipboard, &item_count);
13017 for (ItemCount i = 0; i < item_count; i++)
13018 {
13019 PasteboardItemID item_id = 0;
13020 PasteboardGetItemIdentifier(main_clipboard, i + 1, &item_id);
13021 CFArrayRef flavor_type_array = 0;
13022 PasteboardCopyItemFlavors(main_clipboard, item_id, &flavor_type_array);
13023 for (CFIndex j = 0, nj = CFArrayGetCount(flavor_type_array); j < nj; j++)
13024 {
13025 CFDataRef cf_data;
13026 if (PasteboardCopyItemFlavorData(main_clipboard, item_id, CFSTR("public.utf8-plain-text"), &cf_data) == noErr)
13027 {
13029 int length = (int)CFDataGetLength(cf_data);
13030 g.ClipboardHandlerData.resize(length + 1);
13031 CFDataGetBytes(cf_data, CFRangeMake(0, length), (UInt8*)g.ClipboardHandlerData.Data);
13032 g.ClipboardHandlerData[length] = 0;
13033 CFRelease(cf_data);
13034 return g.ClipboardHandlerData.Data;
13035 }
13036 }
13037 }
13038 return NULL;
13039}
13040
13041#else
13042
13043// Local Dear ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers.
13044static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx)
13045{
13046 ImGuiContext& g = *(ImGuiContext*)user_data_ctx;
13047 return g.ClipboardHandlerData.empty() ? NULL : g.ClipboardHandlerData.begin();
13048}
13049
13050static void SetClipboardTextFn_DefaultImpl(void* user_data_ctx, const char* text)
13051{
13052 ImGuiContext& g = *(ImGuiContext*)user_data_ctx;
13054 const char* text_end = text + strlen(text);
13055 g.ClipboardHandlerData.resize((int)(text_end - text) + 1);
13056 memcpy(&g.ClipboardHandlerData[0], text, (size_t)(text_end - text));
13057 g.ClipboardHandlerData[(int)(text_end - text)] = 0;
13058}
13059
13060#endif
13061
13062// Win32 API IME support (for Asian languages, etc.)
13063#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
13064
13065#include <imm.h>
13066#ifdef _MSC_VER
13067#pragma comment(lib, "imm32")
13068#endif
13069
13070static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport* viewport, ImGuiPlatformImeData* data)
13071{
13072 // Notify OS Input Method Editor of text input position
13073 HWND hwnd = (HWND)viewport->PlatformHandleRaw;
13074 if (hwnd == 0)
13075 return;
13076
13077 //::ImmAssociateContextEx(hwnd, NULL, data->WantVisible ? IACE_DEFAULT : 0);
13078 if (HIMC himc = ::ImmGetContext(hwnd))
13079 {
13080 COMPOSITIONFORM composition_form = {};
13081 composition_form.ptCurrentPos.x = (LONG)data->InputPos.x;
13082 composition_form.ptCurrentPos.y = (LONG)data->InputPos.y;
13083 composition_form.dwStyle = CFS_FORCE_POSITION;
13084 ::ImmSetCompositionWindow(himc, &composition_form);
13085 CANDIDATEFORM candidate_form = {};
13086 candidate_form.dwStyle = CFS_CANDIDATEPOS;
13087 candidate_form.ptCurrentPos.x = (LONG)data->InputPos.x;
13088 candidate_form.ptCurrentPos.y = (LONG)data->InputPos.y;
13089 ::ImmSetCandidateWindow(himc, &candidate_form);
13090 ::ImmReleaseContext(hwnd, himc);
13091 }
13092}
13093
13094#else
13095
13096static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport*, ImGuiPlatformImeData*) {}
13097
13098#endif
13099
13100//-----------------------------------------------------------------------------
13101// [SECTION] METRICS/DEBUGGER WINDOW
13102//-----------------------------------------------------------------------------
13103// - RenderViewportThumbnail() [Internal]
13104// - RenderViewportsThumbnails() [Internal]
13105// - DebugTextEncoding()
13106// - MetricsHelpMarker() [Internal]
13107// - ShowFontAtlas() [Internal]
13108// - ShowMetricsWindow()
13109// - DebugNodeColumns() [Internal]
13110// - DebugNodeDrawList() [Internal]
13111// - DebugNodeDrawCmdShowMeshAndBoundingBox() [Internal]
13112// - DebugNodeFont() [Internal]
13113// - DebugNodeFontGlyph() [Internal]
13114// - DebugNodeStorage() [Internal]
13115// - DebugNodeTabBar() [Internal]
13116// - DebugNodeViewport() [Internal]
13117// - DebugNodeWindow() [Internal]
13118// - DebugNodeWindowSettings() [Internal]
13119// - DebugNodeWindowsList() [Internal]
13120// - DebugNodeWindowsListByBeginStackParent() [Internal]
13121//-----------------------------------------------------------------------------
13122
13123#ifndef IMGUI_DISABLE_DEBUG_TOOLS
13124
13126{
13127 ImGuiContext& g = *GImGui;
13128 ImGuiWindow* window = g.CurrentWindow;
13129
13130 ImVec2 scale = bb.GetSize() / viewport->Size;
13131 ImVec2 off = bb.Min - viewport->Pos * scale;
13132 float alpha_mul = 1.0f;
13133 window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border, alpha_mul * 0.40f));
13134 for (int i = 0; i != g.Windows.Size; i++)
13135 {
13136 ImGuiWindow* thumb_window = g.Windows[i];
13137 if (!thumb_window->WasActive || (thumb_window->Flags & ImGuiWindowFlags_ChildWindow))
13138 continue;
13139
13140 ImRect thumb_r = thumb_window->Rect();
13141 ImRect title_r = thumb_window->TitleBarRect();
13142 thumb_r = ImRect(ImFloor(off + thumb_r.Min * scale), ImFloor(off + thumb_r.Max * scale));
13143 title_r = ImRect(ImFloor(off + title_r.Min * scale), ImFloor(off + ImVec2(title_r.Max.x, title_r.Min.y) * scale) + ImVec2(0,5)); // Exaggerate title bar height
13144 thumb_r.ClipWithFull(bb);
13145 title_r.ClipWithFull(bb);
13146 const bool window_is_focused = (g.NavWindow && thumb_window->RootWindowForTitleBarHighlight == g.NavWindow->RootWindowForTitleBarHighlight);
13147 window->DrawList->AddRectFilled(thumb_r.Min, thumb_r.Max, GetColorU32(ImGuiCol_WindowBg, alpha_mul));
13148 window->DrawList->AddRectFilled(title_r.Min, title_r.Max, GetColorU32(window_is_focused ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg, alpha_mul));
13149 window->DrawList->AddRect(thumb_r.Min, thumb_r.Max, GetColorU32(ImGuiCol_Border, alpha_mul));
13150 window->DrawList->AddText(g.Font, g.FontSize * 1.0f, title_r.Min, GetColorU32(ImGuiCol_Text, alpha_mul), thumb_window->Name, FindRenderedTextEnd(thumb_window->Name));
13151 }
13152 draw_list->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border, alpha_mul));
13153}
13154
13155static void RenderViewportsThumbnails()
13156{
13157 ImGuiContext& g = *GImGui;
13158 ImGuiWindow* window = g.CurrentWindow;
13159
13160 // We don't display full monitor bounds (we could, but it often looks awkward), instead we display just enough to cover all of our viewports.
13161 float SCALE = 1.0f / 8.0f;
13162 ImRect bb_full(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
13163 for (int n = 0; n < g.Viewports.Size; n++)
13164 bb_full.Add(g.Viewports[n]->GetMainRect());
13165 ImVec2 p = window->DC.CursorPos;
13166 ImVec2 off = p - bb_full.Min * SCALE;
13167 for (int n = 0; n < g.Viewports.Size; n++)
13168 {
13169 ImGuiViewportP* viewport = g.Viewports[n];
13170 ImRect viewport_draw_bb(off + (viewport->Pos) * SCALE, off + (viewport->Pos + viewport->Size) * SCALE);
13171 ImGui::DebugRenderViewportThumbnail(window->DrawList, viewport, viewport_draw_bb);
13172 }
13173 ImGui::Dummy(bb_full.GetSize() * SCALE);
13174}
13175
13176// Draw an arbitrary US keyboard layout to visualize translated keys
13178{
13179 const ImVec2 key_size = ImVec2(35.0f, 35.0f);
13180 const float key_rounding = 3.0f;
13181 const ImVec2 key_face_size = ImVec2(25.0f, 25.0f);
13182 const ImVec2 key_face_pos = ImVec2(5.0f, 3.0f);
13183 const float key_face_rounding = 2.0f;
13184 const ImVec2 key_label_pos = ImVec2(7.0f, 4.0f);
13185 const ImVec2 key_step = ImVec2(key_size.x - 1.0f, key_size.y - 1.0f);
13186 const float key_row_offset = 9.0f;
13187
13188 ImVec2 board_min = GetCursorScreenPos();
13189 ImVec2 board_max = ImVec2(board_min.x + 3 * key_step.x + 2 * key_row_offset + 10.0f, board_min.y + 3 * key_step.y + 10.0f);
13190 ImVec2 start_pos = ImVec2(board_min.x + 5.0f - key_step.x, board_min.y);
13191
13192 struct KeyLayoutData { int Row, Col; const char* Label; ImGuiKey Key; };
13193 const KeyLayoutData keys_to_display[] =
13194 {
13195 { 0, 0, "", ImGuiKey_Tab }, { 0, 1, "Q", ImGuiKey_Q }, { 0, 2, "W", ImGuiKey_W }, { 0, 3, "E", ImGuiKey_E }, { 0, 4, "R", ImGuiKey_R },
13196 { 1, 0, "", ImGuiKey_CapsLock }, { 1, 1, "A", ImGuiKey_A }, { 1, 2, "S", ImGuiKey_S }, { 1, 3, "D", ImGuiKey_D }, { 1, 4, "F", ImGuiKey_F },
13197 { 2, 0, "", ImGuiKey_LeftShift },{ 2, 1, "Z", ImGuiKey_Z }, { 2, 2, "X", ImGuiKey_X }, { 2, 3, "C", ImGuiKey_C }, { 2, 4, "V", ImGuiKey_V }
13198 };
13199
13200 // Elements rendered manually via ImDrawList API are not clipped automatically.
13201 // While not strictly necessary, here IsItemVisible() is used to avoid rendering these shapes when they are out of view.
13202 Dummy(board_max - board_min);
13203 if (!IsItemVisible())
13204 return;
13205 draw_list->PushClipRect(board_min, board_max, true);
13206 for (int n = 0; n < IM_ARRAYSIZE(keys_to_display); n++)
13207 {
13208 const KeyLayoutData* key_data = &keys_to_display[n];
13209 ImVec2 key_min = ImVec2(start_pos.x + key_data->Col * key_step.x + key_data->Row * key_row_offset, start_pos.y + key_data->Row * key_step.y);
13210 ImVec2 key_max = key_min + key_size;
13211 draw_list->AddRectFilled(key_min, key_max, IM_COL32(204, 204, 204, 255), key_rounding);
13212 draw_list->AddRect(key_min, key_max, IM_COL32(24, 24, 24, 255), key_rounding);
13213 ImVec2 face_min = ImVec2(key_min.x + key_face_pos.x, key_min.y + key_face_pos.y);
13214 ImVec2 face_max = ImVec2(face_min.x + key_face_size.x, face_min.y + key_face_size.y);
13215 draw_list->AddRect(face_min, face_max, IM_COL32(193, 193, 193, 255), key_face_rounding, ImDrawFlags_None, 2.0f);
13216 draw_list->AddRectFilled(face_min, face_max, IM_COL32(252, 252, 252, 255), key_face_rounding);
13217 ImVec2 label_min = ImVec2(key_min.x + key_label_pos.x, key_min.y + key_label_pos.y);
13218 draw_list->AddText(label_min, IM_COL32(64, 64, 64, 255), key_data->Label);
13219 if (ImGui::IsKeyDown(key_data->Key))
13220 draw_list->AddRectFilled(key_min, key_max, IM_COL32(255, 0, 0, 128), key_rounding);
13221 }
13222 draw_list->PopClipRect();
13223}
13224
13225// Helper tool to diagnose between text encoding issues and font loading issues. Pass your UTF-8 string and verify that there are correct.
13226void ImGui::DebugTextEncoding(const char* str)
13227{
13228 Text("Text: \"%s\"", str);
13230 return;
13231 TableSetupColumn("Offset");
13232 TableSetupColumn("UTF-8");
13233 TableSetupColumn("Glyph");
13234 TableSetupColumn("Codepoint");
13236 for (const char* p = str; *p != 0; )
13237 {
13238 unsigned int c;
13239 const int c_utf8_len = ImTextCharFromUtf8(&c, p, NULL);
13241 Text("%d", (int)(p - str));
13243 for (int byte_index = 0; byte_index < c_utf8_len; byte_index++)
13244 {
13245 if (byte_index > 0)
13246 SameLine();
13247 Text("0x%02X", (int)(unsigned char)p[byte_index]);
13248 }
13250 if (GetFont()->FindGlyphNoFallback((ImWchar)c))
13251 TextUnformatted(p, p + c_utf8_len);
13252 else
13253 TextUnformatted((c == IM_UNICODE_CODEPOINT_INVALID) ? "[invalid]" : "[missing]");
13255 Text("U+%04X", (int)c);
13256 p += c_utf8_len;
13257 }
13258 EndTable();
13259}
13260
13261// Avoid naming collision with imgui_demo.cpp's HelpMarker() for unity builds.
13262static void MetricsHelpMarker(const char* desc)
13263{
13264 ImGui::TextDisabled("(?)");
13266 {
13271 }
13272}
13273
13274// [DEBUG] List fonts in a font atlas and display its texture
13276{
13277 for (int i = 0; i < atlas->Fonts.Size; i++)
13278 {
13279 ImFont* font = atlas->Fonts[i];
13280 PushID(font);
13281 DebugNodeFont(font);
13282 PopID();
13283 }
13284 if (TreeNode("Font Atlas", "Font Atlas (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight))
13285 {
13286 ImGuiContext& g = *GImGui;
13288 Checkbox("Tint with Text Color", &cfg->ShowAtlasTintedWithTextColor); // Using text color ensure visibility of core atlas data, but will alter custom colored icons
13289 ImVec4 tint_col = cfg->ShowAtlasTintedWithTextColor ? GetStyleColorVec4(ImGuiCol_Text) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
13291 Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), tint_col, border_col);
13292 TreePop();
13293 }
13294}
13295
13297{
13298 ImGuiContext& g = *GImGui;
13299 ImGuiIO& io = g.IO;
13301 if (cfg->ShowDebugLog)
13303 if (cfg->ShowStackTool)
13305
13306 if (!Begin("Dear ImGui Metrics/Debugger", p_open) || GetCurrentWindow()->BeginCount > 1)
13307 {
13308 End();
13309 return;
13310 }
13311
13312 // Basic info
13313 Text("Dear ImGui %s", GetVersion());
13314 Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
13315 Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3);
13316 Text("%d visible windows, %d active allocations", io.MetricsRenderWindows, io.MetricsActiveAllocations);
13317 //SameLine(); if (SmallButton("GC")) { g.GcCompactAll = true; }
13318
13319 Separator();
13320
13321 // Debugging enums
13322 enum { WRT_OuterRect, WRT_OuterRectClipped, WRT_InnerRect, WRT_InnerClipRect, WRT_WorkRect, WRT_Content, WRT_ContentIdeal, WRT_ContentRegionRect, WRT_Count }; // Windows Rect Type
13323 const char* wrt_rects_names[WRT_Count] = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Content", "ContentIdeal", "ContentRegionRect" };
13324 enum { TRT_OuterRect, TRT_InnerRect, TRT_WorkRect, TRT_HostClipRect, TRT_InnerClipRect, TRT_BackgroundClipRect, TRT_ColumnsRect, TRT_ColumnsWorkRect, TRT_ColumnsClipRect, TRT_ColumnsContentHeadersUsed, TRT_ColumnsContentHeadersIdeal, TRT_ColumnsContentFrozen, TRT_ColumnsContentUnfrozen, TRT_Count }; // Tables Rect Type
13325 const char* trt_rects_names[TRT_Count] = { "OuterRect", "InnerRect", "WorkRect", "HostClipRect", "InnerClipRect", "BackgroundClipRect", "ColumnsRect", "ColumnsWorkRect", "ColumnsClipRect", "ColumnsContentHeadersUsed", "ColumnsContentHeadersIdeal", "ColumnsContentFrozen", "ColumnsContentUnfrozen" };
13326 if (cfg->ShowWindowsRectsType < 0)
13327 cfg->ShowWindowsRectsType = WRT_WorkRect;
13328 if (cfg->ShowTablesRectsType < 0)
13329 cfg->ShowTablesRectsType = TRT_WorkRect;
13330
13331 struct Funcs
13332 {
13333 static ImRect GetTableRect(ImGuiTable* table, int rect_type, int n)
13334 {
13335 ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); // Always using last submitted instance
13336 if (rect_type == TRT_OuterRect) { return table->OuterRect; }
13337 else if (rect_type == TRT_InnerRect) { return table->InnerRect; }
13338 else if (rect_type == TRT_WorkRect) { return table->WorkRect; }
13339 else if (rect_type == TRT_HostClipRect) { return table->HostClipRect; }
13340 else if (rect_type == TRT_InnerClipRect) { return table->InnerClipRect; }
13341 else if (rect_type == TRT_BackgroundClipRect) { return table->BgClipRect; }
13342 else if (rect_type == TRT_ColumnsRect) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->MinX, table->InnerClipRect.Min.y, c->MaxX, table->InnerClipRect.Min.y + table_instance->LastOuterHeight); }
13343 else if (rect_type == TRT_ColumnsWorkRect) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->WorkRect.Min.y, c->WorkMaxX, table->WorkRect.Max.y); }
13344 else if (rect_type == TRT_ColumnsClipRect) { ImGuiTableColumn* c = &table->Columns[n]; return c->ClipRect; }
13345 else if (rect_type == TRT_ColumnsContentHeadersUsed){ ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXHeadersUsed, table->InnerClipRect.Min.y + table_instance->LastFirstRowHeight); } // Note: y1/y2 not always accurate
13346 else if (rect_type == TRT_ColumnsContentHeadersIdeal){ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXHeadersIdeal, table->InnerClipRect.Min.y + table_instance->LastFirstRowHeight); }
13347 else if (rect_type == TRT_ColumnsContentFrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXFrozen, table->InnerClipRect.Min.y + table_instance->LastFrozenHeight); }
13348 else if (rect_type == TRT_ColumnsContentUnfrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y + table_instance->LastFrozenHeight, c->ContentMaxXUnfrozen, table->InnerClipRect.Max.y); }
13349 IM_ASSERT(0);
13350 return ImRect();
13351 }
13352
13353 static ImRect GetWindowRect(ImGuiWindow* window, int rect_type)
13354 {
13355 if (rect_type == WRT_OuterRect) { return window->Rect(); }
13356 else if (rect_type == WRT_OuterRectClipped) { return window->OuterRectClipped; }
13357 else if (rect_type == WRT_InnerRect) { return window->InnerRect; }
13358 else if (rect_type == WRT_InnerClipRect) { return window->InnerClipRect; }
13359 else if (rect_type == WRT_WorkRect) { return window->WorkRect; }
13360 else if (rect_type == WRT_Content) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); }
13361 else if (rect_type == WRT_ContentIdeal) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSizeIdeal); }
13362 else if (rect_type == WRT_ContentRegionRect) { return window->ContentRegionRect; }
13363 IM_ASSERT(0);
13364 return ImRect();
13365 }
13366 };
13367
13368 // Tools
13369 if (TreeNode("Tools"))
13370 {
13371 bool show_encoding_viewer = TreeNode("UTF-8 Encoding viewer");
13372 SameLine();
13373 MetricsHelpMarker("You can also call ImGui::DebugTextEncoding() from your code with a given string to test that your UTF-8 encoding settings are correct.");
13374 if (show_encoding_viewer)
13375 {
13376 static char buf[100] = "";
13377 SetNextItemWidth(-FLT_MIN);
13378 InputText("##Text", buf, IM_ARRAYSIZE(buf));
13379 if (buf[0] != 0)
13380 DebugTextEncoding(buf);
13381 TreePop();
13382 }
13383
13384 // The Item Picker tool is super useful to visually select an item and break into the call-stack of where it was submitted.
13385 if (Checkbox("Show Item Picker", &g.DebugItemPickerActive) && g.DebugItemPickerActive)
13387 SameLine();
13388 MetricsHelpMarker("Will call the IM_DEBUG_BREAK() macro to break in debugger.\nWarning: If you don't have a debugger attached, this will probably crash.");
13389
13390 // Stack Tool is your best friend!
13391 Checkbox("Show Debug Log", &cfg->ShowDebugLog);
13392 SameLine();
13393 MetricsHelpMarker("You can also call ImGui::ShowDebugLogWindow() from your code.");
13394
13395 // Stack Tool is your best friend!
13396 Checkbox("Show Stack Tool", &cfg->ShowStackTool);
13397 SameLine();
13398 MetricsHelpMarker("You can also call ImGui::ShowStackToolWindow() from your code.");
13399
13400 Checkbox("Show windows begin order", &cfg->ShowWindowsBeginOrder);
13401 Checkbox("Show windows rectangles", &cfg->ShowWindowsRects);
13402 SameLine();
13404 cfg->ShowWindowsRects |= Combo("##show_windows_rect_type", &cfg->ShowWindowsRectsType, wrt_rects_names, WRT_Count, WRT_Count);
13405 if (cfg->ShowWindowsRects && g.NavWindow != NULL)
13406 {
13407 BulletText("'%s':", g.NavWindow->Name);
13408 Indent();
13409 for (int rect_n = 0; rect_n < WRT_Count; rect_n++)
13410 {
13411 ImRect r = Funcs::GetWindowRect(g.NavWindow, rect_n);
13412 Text("(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), wrt_rects_names[rect_n]);
13413 }
13414 Unindent();
13415 }
13416
13417 Checkbox("Show tables rectangles", &cfg->ShowTablesRects);
13418 SameLine();
13420 cfg->ShowTablesRects |= Combo("##show_table_rects_type", &cfg->ShowTablesRectsType, trt_rects_names, TRT_Count, TRT_Count);
13421 if (cfg->ShowTablesRects && g.NavWindow != NULL)
13422 {
13423 for (int table_n = 0; table_n < g.Tables.GetMapSize(); table_n++)
13424 {
13425 ImGuiTable* table = g.Tables.TryGetMapData(table_n);
13426 if (table == NULL || table->LastFrameActive < g.FrameCount - 1 || (table->OuterWindow != g.NavWindow && table->InnerWindow != g.NavWindow))
13427 continue;
13428
13429 BulletText("Table 0x%08X (%d columns, in '%s')", table->ID, table->ColumnsCount, table->OuterWindow->Name);
13430 if (IsItemHovered())
13431 GetForegroundDrawList()->AddRect(table->OuterRect.Min - ImVec2(1, 1), table->OuterRect.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f);
13432 Indent();
13433 char buf[128];
13434 for (int rect_n = 0; rect_n < TRT_Count; rect_n++)
13435 {
13436 if (rect_n >= TRT_ColumnsRect)
13437 {
13438 if (rect_n != TRT_ColumnsRect && rect_n != TRT_ColumnsClipRect)
13439 continue;
13440 for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
13441 {
13442 ImRect r = Funcs::GetTableRect(table, rect_n, column_n);
13443 ImFormatString(buf, IM_ARRAYSIZE(buf), "(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) Col %d %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), column_n, trt_rects_names[rect_n]);
13444 Selectable(buf);
13445 if (IsItemHovered())
13446 GetForegroundDrawList()->AddRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f);
13447 }
13448 }
13449 else
13450 {
13451 ImRect r = Funcs::GetTableRect(table, rect_n, -1);
13452 ImFormatString(buf, IM_ARRAYSIZE(buf), "(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), trt_rects_names[rect_n]);
13453 Selectable(buf);
13454 if (IsItemHovered())
13455 GetForegroundDrawList()->AddRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f);
13456 }
13457 }
13458 Unindent();
13459 }
13460 }
13461
13462 TreePop();
13463 }
13464
13465 // Windows
13466 if (TreeNode("Windows", "Windows (%d)", g.Windows.Size))
13467 {
13468 //SetNextItemOpen(true, ImGuiCond_Once);
13469 DebugNodeWindowsList(&g.Windows, "By display order");
13470 DebugNodeWindowsList(&g.WindowsFocusOrder, "By focus order (root windows)");
13471 if (TreeNode("By submission order (begin stack)"))
13472 {
13473 // Here we display windows in their submitted order/hierarchy, however note that the Begin stack doesn't constitute a Parent<>Child relationship!
13475 temp_buffer.resize(0);
13476 for (int i = 0; i < g.Windows.Size; i++)
13477 if (g.Windows[i]->LastFrameActive + 1 >= g.FrameCount)
13478 temp_buffer.push_back(g.Windows[i]);
13479 struct Func { static int IMGUI_CDECL WindowComparerByBeginOrder(const void* lhs, const void* rhs) { return ((int)(*(const ImGuiWindow* const *)lhs)->BeginOrderWithinContext - (*(const ImGuiWindow* const*)rhs)->BeginOrderWithinContext); } };
13480 ImQsort(temp_buffer.Data, (size_t)temp_buffer.Size, sizeof(ImGuiWindow*), Func::WindowComparerByBeginOrder);
13481 DebugNodeWindowsListByBeginStackParent(temp_buffer.Data, temp_buffer.Size, NULL);
13482 TreePop();
13483 }
13484
13485 TreePop();
13486 }
13487
13488 // DrawLists
13489 int drawlist_count = 0;
13490 for (int viewport_i = 0; viewport_i < g.Viewports.Size; viewport_i++)
13491 drawlist_count += g.Viewports[viewport_i]->DrawDataBuilder.GetDrawListCount();
13492 if (TreeNode("DrawLists", "DrawLists (%d)", drawlist_count))
13493 {
13494 Checkbox("Show ImDrawCmd mesh when hovering", &cfg->ShowDrawCmdMesh);
13495 Checkbox("Show ImDrawCmd bounding boxes when hovering", &cfg->ShowDrawCmdBoundingBoxes);
13496 for (int viewport_i = 0; viewport_i < g.Viewports.Size; viewport_i++)
13497 {
13498 ImGuiViewportP* viewport = g.Viewports[viewport_i];
13499 for (int layer_i = 0; layer_i < IM_ARRAYSIZE(viewport->DrawDataBuilder.Layers); layer_i++)
13500 for (int draw_list_i = 0; draw_list_i < viewport->DrawDataBuilder.Layers[layer_i].Size; draw_list_i++)
13501 DebugNodeDrawList(NULL, viewport->DrawDataBuilder.Layers[layer_i][draw_list_i], "DrawList");
13502 }
13503 TreePop();
13504 }
13505
13506 // Viewports
13507 if (TreeNode("Viewports", "Viewports (%d)", g.Viewports.Size))
13508 {
13510 RenderViewportsThumbnails();
13512 for (int i = 0; i < g.Viewports.Size; i++)
13514 TreePop();
13515 }
13516
13517 // Details for Popups
13518 if (TreeNode("Popups", "Popups (%d)", g.OpenPopupStack.Size))
13519 {
13520 for (int i = 0; i < g.OpenPopupStack.Size; i++)
13521 {
13522 // As it's difficult to interact with tree nodes while popups are open, we display everything inline.
13523 const ImGuiPopupData* popup_data = &g.OpenPopupStack[i];
13524 ImGuiWindow* window = popup_data->Window;
13525 BulletText("PopupID: %08x, Window: '%s' (%s%s), BackupNavWindow '%s', ParentWindow '%s'",
13526 popup_data->PopupId, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? "Child;" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? "Menu;" : "",
13527 popup_data->BackupNavWindow ? popup_data->BackupNavWindow->Name : "NULL", window && window->ParentWindow ? window->ParentWindow->Name : "NULL");
13528 }
13529 TreePop();
13530 }
13531
13532 // Details for TabBars
13533 if (TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.GetAliveCount()))
13534 {
13535 for (int n = 0; n < g.TabBars.GetMapSize(); n++)
13536 if (ImGuiTabBar* tab_bar = g.TabBars.TryGetMapData(n))
13537 {
13538 PushID(tab_bar);
13539 DebugNodeTabBar(tab_bar, "TabBar");
13540 PopID();
13541 }
13542 TreePop();
13543 }
13544
13545 // Details for Tables
13546 if (TreeNode("Tables", "Tables (%d)", g.Tables.GetAliveCount()))
13547 {
13548 for (int n = 0; n < g.Tables.GetMapSize(); n++)
13549 if (ImGuiTable* table = g.Tables.TryGetMapData(n))
13550 DebugNodeTable(table);
13551 TreePop();
13552 }
13553
13554 // Details for Fonts
13555 ImFontAtlas* atlas = g.IO.Fonts;
13556 if (TreeNode("Fonts", "Fonts (%d)", atlas->Fonts.Size))
13557 {
13558 ShowFontAtlas(atlas);
13559 TreePop();
13560 }
13561
13562 // Details for InputText
13563 if (TreeNode("InputText"))
13564 {
13566 TreePop();
13567 }
13568
13569 // Details for Docking
13570#ifdef IMGUI_HAS_DOCK
13571 if (TreeNode("Docking"))
13572 {
13573 TreePop();
13574 }
13575#endif // #ifdef IMGUI_HAS_DOCK
13576
13577 // Settings
13578 if (TreeNode("Settings"))
13579 {
13580 if (SmallButton("Clear"))
13582 SameLine();
13583 if (SmallButton("Save to memory"))
13585 SameLine();
13586 if (SmallButton("Save to disk"))
13588 SameLine();
13589 if (g.IO.IniFilename)
13590 Text("\"%s\"", g.IO.IniFilename);
13591 else
13592 TextUnformatted("<NULL>");
13593 Text("SettingsDirtyTimer %.2f", g.SettingsDirtyTimer);
13594 if (TreeNode("SettingsHandlers", "Settings handlers: (%d)", g.SettingsHandlers.Size))
13595 {
13596 for (int n = 0; n < g.SettingsHandlers.Size; n++)
13597 BulletText("%s", g.SettingsHandlers[n].TypeName);
13598 TreePop();
13599 }
13600 if (TreeNode("SettingsWindows", "Settings packed data: Windows: %d bytes", g.SettingsWindows.size()))
13601 {
13602 for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
13603 DebugNodeWindowSettings(settings);
13604 TreePop();
13605 }
13606
13607 if (TreeNode("SettingsTables", "Settings packed data: Tables: %d bytes", g.SettingsTables.size()))
13608 {
13609 for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings))
13610 DebugNodeTableSettings(settings);
13611 TreePop();
13612 }
13613
13614#ifdef IMGUI_HAS_DOCK
13615#endif // #ifdef IMGUI_HAS_DOCK
13616
13617 if (TreeNode("SettingsIniData", "Settings unpacked data (.ini): %d bytes", g.SettingsIniData.size()))
13618 {
13620 TreePop();
13621 }
13622 TreePop();
13623 }
13624
13625 if (TreeNode("Inputs"))
13626 {
13627 Text("KEYBOARD/GAMEPAD/MOUSE KEYS");
13628 {
13629 // We iterate both legacy native range and named ImGuiKey ranges, which is a little odd but this allows displaying the data for old/new backends.
13630 // User code should never have to go through such hoops! You can generally iterate between ImGuiKey_NamedKey_BEGIN and ImGuiKey_NamedKey_END.
13631 Indent();
13632#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO
13633 struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } };
13634#else
13635 struct funcs { static bool IsLegacyNativeDupe(ImGuiKey key) { return key < 512 && GetIO().KeyMap[key] != -1; } }; // Hide Native<>ImGuiKey duplicates when both exists in the array
13636 //Text("Legacy raw:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key++) { if (io.KeysDown[key]) { SameLine(); Text("\"%s\" %d", GetKeyName(key), key); } }
13637#endif
13638 Text("Keys down:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyDown(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); SameLine(); Text("(%.02f)", GetKeyData(key)->DownDuration); }
13639 Text("Keys pressed:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyPressed(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); }
13640 Text("Keys released:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyReleased(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); }
13641 Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : "");
13642 Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; SameLine(); Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public.
13644 Unindent();
13645 }
13646
13647 Text("MOUSE STATE");
13648 {
13649 Indent();
13650 if (IsMousePosValid())
13651 Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y);
13652 else
13653 Text("Mouse pos: <INVALID>");
13654 Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y);
13655 int count = IM_ARRAYSIZE(io.MouseDown);
13656 Text("Mouse down:"); for (int i = 0; i < count; i++) if (IsMouseDown(i)) { SameLine(); Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); }
13657 Text("Mouse clicked:"); for (int i = 0; i < count; i++) if (IsMouseClicked(i)) { SameLine(); Text("b%d (%d)", i, io.MouseClickedCount[i]); }
13658 Text("Mouse released:"); for (int i = 0; i < count; i++) if (IsMouseReleased(i)) { SameLine(); Text("b%d", i); }
13659 Text("Mouse wheel: %.1f", io.MouseWheel);
13660 Text("Pen Pressure: %.1f", io.PenPressure); // Note: currently unused
13661 Unindent();
13662 }
13663
13664 Text("MOUSE WHEELING");
13665 {
13666 Indent();
13667 Text("WheelingWindow: '%s'", g.WheelingWindow ? g.WheelingWindow->Name : "NULL");
13668 Text("WheelingWindowReleaseTimer: %.2f", g.WheelingWindowReleaseTimer);
13669 Text("WheelingAxisAvg[] = { %.3f, %.3f }, Main Axis: %s", g.WheelingAxisAvg.x, g.WheelingAxisAvg.y, (g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? "X" : (g.WheelingAxisAvg.x < g.WheelingAxisAvg.y) ? "Y" : "<none>");
13670 Unindent();
13671 }
13672
13673 Text("KEY OWNERS");
13674 {
13675 Indent();
13676 if (BeginListBox("##owners", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 6)))
13677 {
13678 for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1))
13679 {
13680 ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(key);
13681 if (owner_data->OwnerCurr == ImGuiKeyOwner_None)
13682 continue;
13683 Text("%s: 0x%08X%s", GetKeyName(key), owner_data->OwnerCurr,
13684 owner_data->LockUntilRelease ? " LockUntilRelease" : owner_data->LockThisFrame ? " LockThisFrame" : "");
13685 DebugLocateItemOnHover(owner_data->OwnerCurr);
13686 }
13687 EndListBox();
13688 }
13689 Unindent();
13690 }
13691 Text("SHORTCUT ROUTING");
13692 {
13693 Indent();
13694 if (BeginListBox("##routes", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 6)))
13695 {
13696 for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1))
13697 {
13699 for (ImGuiKeyRoutingIndex idx = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; idx != -1; )
13700 {
13701 char key_chord_name[64];
13702 ImGuiKeyRoutingData* routing_data = &rt->Entries[idx];
13703 GetKeyChordName(key | routing_data->Mods, key_chord_name, IM_ARRAYSIZE(key_chord_name));
13704 Text("%s: 0x%08X", key_chord_name, routing_data->RoutingCurr);
13705 DebugLocateItemOnHover(routing_data->RoutingCurr);
13706 idx = routing_data->NextEntryIndex;
13707 }
13708 }
13709 EndListBox();
13710 }
13711 Text("(ActiveIdUsing: AllKeyboardKeys: %d, NavDirMask: 0x%X)", g.ActiveIdUsingAllKeyboardKeys, g.ActiveIdUsingNavDirMask);
13712 Unindent();
13713 }
13714 TreePop();
13715 }
13716
13717 if (TreeNode("Internal state"))
13718 {
13719 Text("WINDOWING");
13720 Indent();
13721 Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL");
13722 Text("HoveredWindow->Root: '%s'", g.HoveredWindow ? g.HoveredWindow->RootWindow->Name : "NULL");
13723 Text("HoveredWindowUnderMovingWindow: '%s'", g.HoveredWindowUnderMovingWindow ? g.HoveredWindowUnderMovingWindow->Name : "NULL");
13724 Text("MovingWindow: '%s'", g.MovingWindow ? g.MovingWindow->Name : "NULL");
13725 Unindent();
13726
13727 Text("ITEMS");
13728 Indent();
13729 Text("ActiveId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d, Source: %s", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, g.ActiveIdAllowOverlap, GetInputSourceName(g.ActiveIdSource));
13731 Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL");
13732 Text("ActiveIdUsing: AllKeyboardKeys: %d, NavDirMask: %X", g.ActiveIdUsingAllKeyboardKeys, g.ActiveIdUsingNavDirMask);
13733 Text("HoveredId: 0x%08X (%.2f sec), AllowOverlap: %d", g.HoveredIdPreviousFrame, g.HoveredIdTimer, g.HoveredIdAllowOverlap); // Not displaying g.HoveredId as it is update mid-frame
13734 Text("HoverDelayId: 0x%08X, Timer: %.2f, ClearTimer: %.2f", g.HoverDelayId, g.HoverDelayTimer, g.HoverDelayClearTimer);
13735 Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize);
13737 Unindent();
13738
13739 Text("NAV,FOCUS");
13740 Indent();
13741 Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL");
13742 Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer);
13744 Text("NavInputSource: %s", GetInputSourceName(g.NavInputSource));
13745 Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible);
13746 Text("NavActivateId/DownId/PressedId: %08X/%08X/%08X", g.NavActivateId, g.NavActivateDownId, g.NavActivatePressedId);
13747 Text("NavActivateFlags: %04X", g.NavActivateFlags);
13748 Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover);
13749 Text("NavFocusScopeId = 0x%08X", g.NavFocusScopeId);
13750 Text("NavWindowingTarget: '%s'", g.NavWindowingTarget ? g.NavWindowingTarget->Name : "NULL");
13751 Unindent();
13752
13753 TreePop();
13754 }
13755
13756 // Overlay: Display windows Rectangles and Begin Order
13757 if (cfg->ShowWindowsRects || cfg->ShowWindowsBeginOrder)
13758 {
13759 for (int n = 0; n < g.Windows.Size; n++)
13760 {
13761 ImGuiWindow* window = g.Windows[n];
13762 if (!window->WasActive)
13763 continue;
13764 ImDrawList* draw_list = GetForegroundDrawList(window);
13765 if (cfg->ShowWindowsRects)
13766 {
13767 ImRect r = Funcs::GetWindowRect(window, cfg->ShowWindowsRectsType);
13768 draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255));
13769 }
13771 {
13772 char buf[32];
13773 ImFormatString(buf, IM_ARRAYSIZE(buf), "%d", window->BeginOrderWithinContext);
13774 float font_size = GetFontSize();
13775 draw_list->AddRectFilled(window->Pos, window->Pos + ImVec2(font_size, font_size), IM_COL32(200, 100, 100, 255));
13776 draw_list->AddText(window->Pos, IM_COL32(255, 255, 255, 255), buf);
13777 }
13778 }
13779 }
13780
13781 // Overlay: Display Tables Rectangles
13782 if (cfg->ShowTablesRects)
13783 {
13784 for (int table_n = 0; table_n < g.Tables.GetMapSize(); table_n++)
13785 {
13786 ImGuiTable* table = g.Tables.TryGetMapData(table_n);
13787 if (table == NULL || table->LastFrameActive < g.FrameCount - 1)
13788 continue;
13789 ImDrawList* draw_list = GetForegroundDrawList(table->OuterWindow);
13790 if (cfg->ShowTablesRectsType >= TRT_ColumnsRect)
13791 {
13792 for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
13793 {
13794 ImRect r = Funcs::GetTableRect(table, cfg->ShowTablesRectsType, column_n);
13795 ImU32 col = (table->HoveredColumnBody == column_n) ? IM_COL32(255, 255, 128, 255) : IM_COL32(255, 0, 128, 255);
13796 float thickness = (table->HoveredColumnBody == column_n) ? 3.0f : 1.0f;
13797 draw_list->AddRect(r.Min, r.Max, col, 0.0f, 0, thickness);
13798 }
13799 }
13800 else
13801 {
13802 ImRect r = Funcs::GetTableRect(table, cfg->ShowTablesRectsType, -1);
13803 draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255));
13804 }
13805 }
13806 }
13807
13808#ifdef IMGUI_HAS_DOCK
13809 // Overlay: Display Docking info
13810 if (show_docking_nodes && g.IO.KeyCtrl)
13811 {
13812 }
13813#endif // #ifdef IMGUI_HAS_DOCK
13814
13815 End();
13816}
13817
13818// [DEBUG] Display contents of Columns
13820{
13821 if (!TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags))
13822 return;
13823 BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX);
13824 for (int column_n = 0; column_n < columns->Columns.Size; column_n++)
13825 BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, GetColumnOffsetFromNorm(columns, columns->Columns[column_n].OffsetNorm));
13826 TreePop();
13827}
13828
13829// [DEBUG] Display contents of ImDrawList
13830void ImGui::DebugNodeDrawList(ImGuiWindow* window, const ImDrawList* draw_list, const char* label)
13831{
13832 ImGuiContext& g = *GImGui;
13834 int cmd_count = draw_list->CmdBuffer.Size;
13835 if (cmd_count > 0 && draw_list->CmdBuffer.back().ElemCount == 0 && draw_list->CmdBuffer.back().UserCallback == NULL)
13836 cmd_count--;
13837 bool node_open = TreeNode(draw_list, "%s: '%s' %d vtx, %d indices, %d cmds", label, draw_list->_OwnerName ? draw_list->_OwnerName : "", draw_list->VtxBuffer.Size, draw_list->IdxBuffer.Size, cmd_count);
13838 if (draw_list == GetWindowDrawList())
13839 {
13840 SameLine();
13841 TextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f), "CURRENTLY APPENDING"); // Can't display stats for active draw list! (we don't have the data double-buffered)
13842 if (node_open)
13843 TreePop();
13844 return;
13845 }
13846
13847 ImDrawList* fg_draw_list = GetForegroundDrawList(window); // Render additional visuals into the top-most draw list
13848 if (window && IsItemHovered() && fg_draw_list)
13849 fg_draw_list->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255));
13850 if (!node_open)
13851 return;
13852
13853 if (window && !window->WasActive)
13854 TextDisabled("Warning: owning Window is inactive. This DrawList is not being rendered!");
13855
13856 for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.Data; pcmd < draw_list->CmdBuffer.Data + cmd_count; pcmd++)
13857 {
13858 if (pcmd->UserCallback)
13859 {
13860 BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData);
13861 continue;
13862 }
13863
13864 char buf[300];
13865 ImFormatString(buf, IM_ARRAYSIZE(buf), "DrawCmd:%5d tris, Tex 0x%p, ClipRect (%4.0f,%4.0f)-(%4.0f,%4.0f)",
13866 pcmd->ElemCount / 3, (void*)(intptr_t)pcmd->TextureId,
13867 pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w);
13868 bool pcmd_node_open = TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "%s", buf);
13869 if (IsItemHovered() && (cfg->ShowDrawCmdMesh || cfg->ShowDrawCmdBoundingBoxes) && fg_draw_list)
13870 DebugNodeDrawCmdShowMeshAndBoundingBox(fg_draw_list, draw_list, pcmd, cfg->ShowDrawCmdMesh, cfg->ShowDrawCmdBoundingBoxes);
13871 if (!pcmd_node_open)
13872 continue;
13873
13874 // Calculate approximate coverage area (touched pixel count)
13875 // This will be in pixels squared as long there's no post-scaling happening to the renderer output.
13876 const ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL;
13877 const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data + pcmd->VtxOffset;
13878 float total_area = 0.0f;
13879 for (unsigned int idx_n = pcmd->IdxOffset; idx_n < pcmd->IdxOffset + pcmd->ElemCount; )
13880 {
13881 ImVec2 triangle[3];
13882 for (int n = 0; n < 3; n++, idx_n++)
13883 triangle[n] = vtx_buffer[idx_buffer ? idx_buffer[idx_n] : idx_n].pos;
13884 total_area += ImTriangleArea(triangle[0], triangle[1], triangle[2]);
13885 }
13886
13887 // Display vertex information summary. Hover to get all triangles drawn in wire-frame
13888 ImFormatString(buf, IM_ARRAYSIZE(buf), "Mesh: ElemCount: %d, VtxOffset: +%d, IdxOffset: +%d, Area: ~%0.f px", pcmd->ElemCount, pcmd->VtxOffset, pcmd->IdxOffset, total_area);
13889 Selectable(buf);
13890 if (IsItemHovered() && fg_draw_list)
13891 DebugNodeDrawCmdShowMeshAndBoundingBox(fg_draw_list, draw_list, pcmd, true, false);
13892
13893 // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted.
13894 ImGuiListClipper clipper;
13895 clipper.Begin(pcmd->ElemCount / 3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible.
13896 while (clipper.Step())
13897 for (int prim = clipper.DisplayStart, idx_i = pcmd->IdxOffset + clipper.DisplayStart * 3; prim < clipper.DisplayEnd; prim++)
13898 {
13899 char* buf_p = buf, * buf_end = buf + IM_ARRAYSIZE(buf);
13900 ImVec2 triangle[3];
13901 for (int n = 0; n < 3; n++, idx_i++)
13902 {
13903 const ImDrawVert& v = vtx_buffer[idx_buffer ? idx_buffer[idx_i] : idx_i];
13904 triangle[n] = v.pos;
13905 buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n",
13906 (n == 0) ? "Vert:" : " ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col);
13907 }
13908
13909 Selectable(buf, false);
13910 if (fg_draw_list && IsItemHovered())
13911 {
13912 ImDrawListFlags backup_flags = fg_draw_list->Flags;
13913 fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles.
13914 fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), ImDrawFlags_Closed, 1.0f);
13915 fg_draw_list->Flags = backup_flags;
13916 }
13917 }
13918 TreePop();
13919 }
13920 TreePop();
13921}
13922
13923// [DEBUG] Display mesh/aabb of a ImDrawCmd
13924void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb)
13925{
13926 IM_ASSERT(show_mesh || show_aabb);
13927
13928 // Draw wire-frame version of all triangles
13929 ImRect clip_rect = draw_cmd->ClipRect;
13930 ImRect vtxs_rect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
13931 ImDrawListFlags backup_flags = out_draw_list->Flags;
13932 out_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles.
13933 for (unsigned int idx_n = draw_cmd->IdxOffset, idx_end = draw_cmd->IdxOffset + draw_cmd->ElemCount; idx_n < idx_end; )
13934 {
13935 ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; // We don't hold on those pointers past iterations as ->AddPolyline() may invalidate them if out_draw_list==draw_list
13936 ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data + draw_cmd->VtxOffset;
13937
13938 ImVec2 triangle[3];
13939 for (int n = 0; n < 3; n++, idx_n++)
13940 vtxs_rect.Add((triangle[n] = vtx_buffer[idx_buffer ? idx_buffer[idx_n] : idx_n].pos));
13941 if (show_mesh)
13942 out_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), ImDrawFlags_Closed, 1.0f); // In yellow: mesh triangles
13943 }
13944 // Draw bounding boxes
13945 if (show_aabb)
13946 {
13947 out_draw_list->AddRect(ImFloor(clip_rect.Min), ImFloor(clip_rect.Max), IM_COL32(255, 0, 255, 255)); // In pink: clipping rectangle submitted to GPU
13948 out_draw_list->AddRect(ImFloor(vtxs_rect.Min), ImFloor(vtxs_rect.Max), IM_COL32(0, 255, 255, 255)); // In cyan: bounding box of triangles
13949 }
13950 out_draw_list->Flags = backup_flags;
13951}
13952
13953// [DEBUG] Display details for a single font, called by ShowStyleEditor().
13955{
13956 bool opened = TreeNode(font, "Font: \"%s\"\n%.2f px, %d glyphs, %d file(s)",
13957 font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount);
13958 SameLine();
13959 if (SmallButton("Set as default"))
13960 GetIO().FontDefault = font;
13961 if (!opened)
13962 return;
13963
13964 // Display preview text
13965 PushFont(font);
13966 Text("The quick brown fox jumps over the lazy dog");
13967 PopFont();
13968
13969 // Display details
13971 DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f");
13972 SameLine(); MetricsHelpMarker(
13973 "Note than the default embedded font is NOT meant to be scaled.\n\n"
13974 "Font are currently rendered into bitmaps at a given size at the time of building the atlas. "
13975 "You may oversample them to get some flexibility with scaling. "
13976 "You can also render at multiple sizes and select which one to use at runtime.\n\n"
13977 "(Glimmer of hope: the atlas system will be rewritten in the future to make scaling more flexible.)");
13978 Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent);
13979 char c_str[5];
13980 Text("Fallback character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->FallbackChar), font->FallbackChar);
13981 Text("Ellipsis character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->EllipsisChar), font->EllipsisChar);
13982 const int surface_sqrt = (int)ImSqrt((float)font->MetricsTotalSurface);
13983 Text("Texture Area: about %d px ~%dx%d px", font->MetricsTotalSurface, surface_sqrt, surface_sqrt);
13984 for (int config_i = 0; config_i < font->ConfigDataCount; config_i++)
13985 if (font->ConfigData)
13986 if (const ImFontConfig* cfg = &font->ConfigData[config_i])
13987 BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d, Offset: (%.1f,%.1f)",
13988 config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH, cfg->GlyphOffset.x, cfg->GlyphOffset.y);
13989
13990 // Display all glyphs of the fonts in separate pages of 256 characters
13991 if (TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size))
13992 {
13993 ImDrawList* draw_list = GetWindowDrawList();
13994 const ImU32 glyph_col = GetColorU32(ImGuiCol_Text);
13995 const float cell_size = font->FontSize * 1;
13996 const float cell_spacing = GetStyle().ItemSpacing.y;
13997 for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256)
13998 {
13999 // Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k)
14000 // This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT
14001 // is large // (if ImWchar==ImWchar32 we will do at least about 272 queries here)
14002 if (!(base & 4095) && font->IsGlyphRangeUnused(base, base + 4095))
14003 {
14004 base += 4096 - 256;
14005 continue;
14006 }
14007
14008 int count = 0;
14009 for (unsigned int n = 0; n < 256; n++)
14010 if (font->FindGlyphNoFallback((ImWchar)(base + n)))
14011 count++;
14012 if (count <= 0)
14013 continue;
14014 if (!TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph"))
14015 continue;
14016
14017 // Draw a 16x16 grid of glyphs
14018 ImVec2 base_pos = GetCursorScreenPos();
14019 for (unsigned int n = 0; n < 256; n++)
14020 {
14021 // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions
14022 // available here and thus cannot easily generate a zero-terminated UTF-8 encoded string.
14023 ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing));
14024 ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size);
14025 const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n));
14026 draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50));
14027 if (!glyph)
14028 continue;
14029 font->RenderChar(draw_list, cell_size, cell_p1, glyph_col, (ImWchar)(base + n));
14030 if (IsMouseHoveringRect(cell_p1, cell_p2) && BeginTooltip())
14031 {
14032 DebugNodeFontGlyph(font, glyph);
14033 EndTooltip();
14034 }
14035 }
14036 Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16));
14037 TreePop();
14038 }
14039 TreePop();
14040 }
14041 TreePop();
14042}
14043
14045{
14046 Text("Codepoint: U+%04X", glyph->Codepoint);
14047 Separator();
14048 Text("Visible: %d", glyph->Visible);
14049 Text("AdvanceX: %.1f", glyph->AdvanceX);
14050 Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1);
14051 Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1);
14052}
14053
14054// [DEBUG] Display contents of ImGuiStorage
14055void ImGui::DebugNodeStorage(ImGuiStorage* storage, const char* label)
14056{
14057 if (!TreeNode(label, "%s: %d entries, %d bytes", label, storage->Data.Size, storage->Data.size_in_bytes()))
14058 return;
14059 for (int n = 0; n < storage->Data.Size; n++)
14060 {
14061 const ImGuiStorage::ImGuiStoragePair& p = storage->Data[n];
14062 BulletText("Key 0x%08X Value { i: %d }", p.key, p.val_i); // Important: we currently don't store a type, real value may not be integer.
14063 }
14064 TreePop();
14065}
14066
14067// [DEBUG] Display contents of ImGuiTabBar
14068void ImGui::DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label)
14069{
14070 // Standalone tab bars (not associated to docking/windows functionality) currently hold no discernible strings.
14071 char buf[256];
14072 char* p = buf;
14073 const char* buf_end = buf + IM_ARRAYSIZE(buf);
14074 const bool is_active = (tab_bar->PrevFrameVisible >= GetFrameCount() - 2);
14075 p += ImFormatString(p, buf_end - p, "%s 0x%08X (%d tabs)%s", label, tab_bar->ID, tab_bar->Tabs.Size, is_active ? "" : " *Inactive*");
14076 p += ImFormatString(p, buf_end - p, " { ");
14077 for (int tab_n = 0; tab_n < ImMin(tab_bar->Tabs.Size, 3); tab_n++)
14078 {
14079 ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
14080 p += ImFormatString(p, buf_end - p, "%s'%s'",
14081 tab_n > 0 ? ", " : "", TabBarGetTabName(tab_bar, tab));
14082 }
14083 p += ImFormatString(p, buf_end - p, (tab_bar->Tabs.Size > 3) ? " ... }" : " } ");
14085 bool open = TreeNode(label, "%s", buf);
14086 if (!is_active) { PopStyleColor(); }
14087 if (is_active && IsItemHovered())
14088 {
14089 ImDrawList* draw_list = GetForegroundDrawList();
14090 draw_list->AddRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max, IM_COL32(255, 255, 0, 255));
14091 draw_list->AddLine(ImVec2(tab_bar->ScrollingRectMinX, tab_bar->BarRect.Min.y), ImVec2(tab_bar->ScrollingRectMinX, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255));
14092 draw_list->AddLine(ImVec2(tab_bar->ScrollingRectMaxX, tab_bar->BarRect.Min.y), ImVec2(tab_bar->ScrollingRectMaxX, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255));
14093 }
14094 if (open)
14095 {
14096 for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
14097 {
14098 ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
14099 PushID(tab);
14100 if (SmallButton("<")) { TabBarQueueReorder(tab_bar, tab, -1); } SameLine(0, 2);
14101 if (SmallButton(">")) { TabBarQueueReorder(tab_bar, tab, +1); } SameLine();
14102 Text("%02d%c Tab 0x%08X '%s' Offset: %.2f, Width: %.2f/%.2f",
14103 tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, TabBarGetTabName(tab_bar, tab), tab->Offset, tab->Width, tab->ContentWidth);
14104 PopID();
14105 }
14106 TreePop();
14107 }
14108}
14109
14111{
14113 if (TreeNode("viewport0", "Viewport #%d", 0))
14114 {
14115 ImGuiWindowFlags flags = viewport->Flags;
14116 BulletText("Main Pos: (%.0f,%.0f), Size: (%.0f,%.0f)\nWorkArea Offset Left: %.0f Top: %.0f, Right: %.0f, Bottom: %.0f",
14117 viewport->Pos.x, viewport->Pos.y, viewport->Size.x, viewport->Size.y,
14118 viewport->WorkOffsetMin.x, viewport->WorkOffsetMin.y, viewport->WorkOffsetMax.x, viewport->WorkOffsetMax.y);
14119 BulletText("Flags: 0x%04X =%s%s%s", viewport->Flags,
14120 (flags & ImGuiViewportFlags_IsPlatformWindow) ? " IsPlatformWindow" : "",
14121 (flags & ImGuiViewportFlags_IsPlatformMonitor) ? " IsPlatformMonitor" : "",
14122 (flags & ImGuiViewportFlags_OwnedByApp) ? " OwnedByApp" : "");
14123 for (int layer_i = 0; layer_i < IM_ARRAYSIZE(viewport->DrawDataBuilder.Layers); layer_i++)
14124 for (int draw_list_i = 0; draw_list_i < viewport->DrawDataBuilder.Layers[layer_i].Size; draw_list_i++)
14125 DebugNodeDrawList(NULL, viewport->DrawDataBuilder.Layers[layer_i][draw_list_i], "DrawList");
14126 TreePop();
14127 }
14128}
14129
14130void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label)
14131{
14132 if (window == NULL)
14133 {
14134 BulletText("%s: NULL", label);
14135 return;
14136 }
14137
14138 ImGuiContext& g = *GImGui;
14139 const bool is_active = window->WasActive;
14142 const bool open = TreeNodeEx(label, tree_node_flags, "%s '%s'%s", label, window->Name, is_active ? "" : " *Inactive*");
14143 if (!is_active) { PopStyleColor(); }
14144 if (IsItemHovered() && is_active)
14145 GetForegroundDrawList(window)->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255));
14146 if (!open)
14147 return;
14148
14149 if (window->MemoryCompacted)
14150 TextDisabled("Note: some memory buffers have been compacted/freed.");
14151
14152 ImGuiWindowFlags flags = window->Flags;
14153 DebugNodeDrawList(window, window->DrawList, "DrawList");
14154 BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), ContentSize (%.1f,%.1f) Ideal (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->ContentSize.x, window->ContentSize.y, window->ContentSizeIdeal.x, window->ContentSizeIdeal.y);
14155 BulletText("Flags: 0x%08X (%s%s%s%s%s%s%s%s%s..)", flags,
14156 (flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "",
14157 (flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "",
14158 (flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : "");
14159 BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f) Scrollbar:%s%s", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y, window->ScrollbarX ? "X" : "", window->ScrollbarY ? "Y" : "");
14160 BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1);
14161 BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems);
14162 for (int layer = 0; layer < ImGuiNavLayer_COUNT; layer++)
14163 {
14164 ImRect r = window->NavRectRel[layer];
14165 if (r.Min.x >= r.Max.y && r.Min.y >= r.Max.y)
14166 BulletText("NavLastIds[%d]: 0x%08X", layer, window->NavLastIds[layer]);
14167 else
14168 BulletText("NavLastIds[%d]: 0x%08X at +(%.1f,%.1f)(%.1f,%.1f)", layer, window->NavLastIds[layer], r.Min.x, r.Min.y, r.Max.x, r.Max.y);
14169 DebugLocateItemOnHover(window->NavLastIds[layer]);
14170 }
14171 BulletText("NavLayersActiveMask: %X, NavLastChildNavWindow: %s", window->DC.NavLayersActiveMask, window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL");
14172 if (window->RootWindow != window) { DebugNodeWindow(window->RootWindow, "RootWindow"); }
14173 if (window->ParentWindow != NULL) { DebugNodeWindow(window->ParentWindow, "ParentWindow"); }
14174 if (window->DC.ChildWindows.Size > 0) { DebugNodeWindowsList(&window->DC.ChildWindows, "ChildWindows"); }
14175 if (window->ColumnsStorage.Size > 0 && TreeNode("Columns", "Columns sets (%d)", window->ColumnsStorage.Size))
14176 {
14177 for (int n = 0; n < window->ColumnsStorage.Size; n++)
14178 DebugNodeColumns(&window->ColumnsStorage[n]);
14179 TreePop();
14180 }
14181 DebugNodeStorage(&window->StateStorage, "Storage");
14182 TreePop();
14183}
14184
14186{
14187 if (settings->WantDelete)
14188 BeginDisabled();
14189 Text("0x%08X \"%s\" Pos (%d,%d) Size (%d,%d) Collapsed=%d",
14190 settings->ID, settings->GetName(), settings->Pos.x, settings->Pos.y, settings->Size.x, settings->Size.y, settings->Collapsed);
14191 if (settings->WantDelete)
14192 EndDisabled();
14193}
14194
14196{
14197 if (!TreeNode(label, "%s (%d)", label, windows->Size))
14198 return;
14199 for (int i = windows->Size - 1; i >= 0; i--) // Iterate front to back
14200 {
14201 PushID((*windows)[i]);
14202 DebugNodeWindow((*windows)[i], "Window");
14203 PopID();
14204 }
14205 TreePop();
14206}
14207
14208// FIXME-OPT: This is technically suboptimal, but it is simpler this way.
14209void ImGui::DebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows, int windows_size, ImGuiWindow* parent_in_begin_stack)
14210{
14211 for (int i = 0; i < windows_size; i++)
14212 {
14213 ImGuiWindow* window = windows[i];
14214 if (window->ParentWindowInBeginStack != parent_in_begin_stack)
14215 continue;
14216 char buf[20];
14217 ImFormatString(buf, IM_ARRAYSIZE(buf), "[%04d] Window", window->BeginOrderWithinContext);
14218 //BulletText("[%04d] Window '%s'", window->BeginOrderWithinContext, window->Name);
14219 DebugNodeWindow(window, buf);
14220 Indent();
14221 DebugNodeWindowsListByBeginStackParent(windows + i + 1, windows_size - i - 1, window);
14222 Unindent();
14223 }
14224}
14225
14226//-----------------------------------------------------------------------------
14227// [SECTION] DEBUG LOG WINDOW
14228//-----------------------------------------------------------------------------
14229
14230void ImGui::DebugLog(const char* fmt, ...)
14231{
14232 va_list args;
14233 va_start(args, fmt);
14234 DebugLogV(fmt, args);
14235 va_end(args);
14236}
14237
14238void ImGui::DebugLogV(const char* fmt, va_list args)
14239{
14240 ImGuiContext& g = *GImGui;
14241 const int old_size = g.DebugLogBuf.size();
14242 g.DebugLogBuf.appendf("[%05d] ", g.FrameCount);
14243 g.DebugLogBuf.appendfv(fmt, args);
14245 IMGUI_DEBUG_PRINTF("%s", g.DebugLogBuf.begin() + old_size);
14246 g.DebugLogIndex.append(g.DebugLogBuf.c_str(), old_size, g.DebugLogBuf.size());
14247}
14248
14250{
14251 ImGuiContext& g = *GImGui;
14254 if (!Begin("Dear ImGui Debug Log", p_open) || GetCurrentWindow()->BeginCount > 1)
14255 {
14256 End();
14257 return;
14258 }
14259
14261 Text("Log events:");
14267 SameLine(); if (CheckboxFlags("Clipper", &g.DebugLogFlags, ImGuiDebugLogFlags_EventClipper)) { g.DebugLogClipperAutoDisableFrames = 2; } if (IsItemHovered()) SetTooltip("Clipper log auto-disabled after 2 frames");
14269
14270 if (SmallButton("Clear"))
14271 {
14272 g.DebugLogBuf.clear();
14273 g.DebugLogIndex.clear();
14274 }
14275 SameLine();
14276 if (SmallButton("Copy"))
14279
14280 ImGuiListClipper clipper;
14281 clipper.Begin(g.DebugLogIndex.size());
14282 while (clipper.Step())
14283 for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++)
14284 {
14285 const char* line_begin = g.DebugLogIndex.get_line_begin(g.DebugLogBuf.c_str(), line_no);
14286 const char* line_end = g.DebugLogIndex.get_line_end(g.DebugLogBuf.c_str(), line_no);
14287 TextUnformatted(line_begin, line_end);
14288 ImRect text_rect = g.LastItemData.Rect;
14289 if (IsItemHovered())
14290 for (const char* p = line_begin; p < line_end - 10; p++)
14291 {
14292 ImGuiID id = 0;
14293 if (p[0] != '0' || (p[1] != 'x' && p[1] != 'X') || sscanf(p + 2, "%X", &id) != 1)
14294 continue;
14295 ImVec2 p0 = CalcTextSize(line_begin, p);
14296 ImVec2 p1 = CalcTextSize(p, p + 10);
14297 g.LastItemData.Rect = ImRect(text_rect.Min + ImVec2(p0.x, 0.0f), text_rect.Min + ImVec2(p0.x + p1.x, p1.y));
14300 p += 10;
14301 }
14302 }
14303 if (GetScrollY() >= GetScrollMaxY())
14304 SetScrollHereY(1.0f);
14305 EndChild();
14306
14307 End();
14308}
14309
14310//-----------------------------------------------------------------------------
14311// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, STACK TOOL)
14312//-----------------------------------------------------------------------------
14313
14314static const ImU32 DEBUG_LOCATE_ITEM_COLOR = IM_COL32(0, 255, 0, 255); // Green
14315
14317{
14318 ImGuiContext& g = *GImGui;
14319 g.DebugLocateId = target_id;
14320 g.DebugLocateFrames = 2;
14321}
14322
14324{
14326 return;
14327 ImGuiContext& g = *GImGui;
14328 DebugLocateItem(target_id);
14329 GetForegroundDrawList(g.CurrentWindow)->AddRect(g.LastItemData.Rect.Min - ImVec2(3.0f, 3.0f), g.LastItemData.Rect.Max + ImVec2(3.0f, 3.0f), DEBUG_LOCATE_ITEM_COLOR);
14330}
14331
14333{
14334 ImGuiContext& g = *GImGui;
14335 ImGuiLastItemData item_data = g.LastItemData;
14336 g.DebugLocateId = 0;
14338 ImRect r = item_data.Rect;
14339 r.Expand(3.0f);
14340 ImVec2 p1 = g.IO.MousePos;
14341 ImVec2 p2 = ImVec2((p1.x < r.Min.x) ? r.Min.x : (p1.x > r.Max.x) ? r.Max.x : p1.x, (p1.y < r.Min.y) ? r.Min.y : (p1.y > r.Max.y) ? r.Max.y : p1.y);
14342 draw_list->AddRect(r.Min, r.Max, DEBUG_LOCATE_ITEM_COLOR);
14343 draw_list->AddLine(p1, p2, DEBUG_LOCATE_ITEM_COLOR);
14344}
14345
14346// [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack.
14347void ImGui::UpdateDebugToolItemPicker()
14348{
14349 ImGuiContext& g = *GImGui;
14351 if (!g.DebugItemPickerActive)
14352 return;
14353
14354 const ImGuiID hovered_id = g.HoveredIdPreviousFrame;
14355 SetMouseCursor(ImGuiMouseCursor_Hand);
14356 if (IsKeyPressed(ImGuiKey_Escape))
14357 g.DebugItemPickerActive = false;
14358 const bool change_mapping = g.IO.KeyMods == (ImGuiMod_Ctrl | ImGuiMod_Shift);
14359 if (!change_mapping && IsMouseClicked(g.DebugItemPickerMouseButton) && hovered_id)
14360 {
14361 g.DebugItemPickerBreakId = hovered_id;
14362 g.DebugItemPickerActive = false;
14363 }
14364 for (int mouse_button = 0; mouse_button < 3; mouse_button++)
14365 if (change_mapping && IsMouseClicked(mouse_button))
14366 g.DebugItemPickerMouseButton = (ImU8)mouse_button;
14367 SetNextWindowBgAlpha(0.70f);
14368 if (!BeginTooltip())
14369 return;
14370 Text("HoveredId: 0x%08X", hovered_id);
14371 Text("Press ESC to abort picking.");
14372 const char* mouse_button_names[] = { "Left", "Right", "Middle" };
14373 if (change_mapping)
14374 Text("Remap w/ Ctrl+Shift: click anywhere to select new mouse button.");
14375 else
14376 TextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), "Click %s Button to break in debugger! (remap w/ Ctrl+Shift)", mouse_button_names[g.DebugItemPickerMouseButton]);
14377 EndTooltip();
14378}
14379
14380// [DEBUG] Stack Tool: update queries. Called by NewFrame()
14381void ImGui::UpdateDebugToolStackQueries()
14382{
14383 ImGuiContext& g = *GImGui;
14384 ImGuiStackTool* tool = &g.DebugStackTool;
14385
14386 // Clear hook when stack tool is not visible
14387 g.DebugHookIdInfo = 0;
14388 if (g.FrameCount != tool->LastActiveFrame + 1)
14389 return;
14390
14391 // Update queries. The steps are: -1: query Stack, >= 0: query each stack item
14392 // We can only perform 1 ID Info query every frame. This is designed so the GetID() tests are cheap and constant-time
14394 if (tool->QueryId != query_id)
14395 {
14396 tool->QueryId = query_id;
14397 tool->StackLevel = -1;
14398 tool->Results.resize(0);
14399 }
14400 if (query_id == 0)
14401 return;
14402
14403 // Advance to next stack level when we got our result, or after 2 frames (in case we never get a result)
14404 int stack_level = tool->StackLevel;
14405 if (stack_level >= 0 && stack_level < tool->Results.Size)
14406 if (tool->Results[stack_level].QuerySuccess || tool->Results[stack_level].QueryFrameCount > 2)
14407 tool->StackLevel++;
14408
14409 // Update hook
14410 stack_level = tool->StackLevel;
14411 if (stack_level == -1)
14412 g.DebugHookIdInfo = query_id;
14413 if (stack_level >= 0 && stack_level < tool->Results.Size)
14414 {
14415 g.DebugHookIdInfo = tool->Results[stack_level].ID;
14416 tool->Results[stack_level].QueryFrameCount++;
14417 }
14418}
14419
14420// [DEBUG] Stack tool: hooks called by GetID() family functions
14421void ImGui::DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* data_id, const void* data_id_end)
14422{
14423 ImGuiContext& g = *GImGui;
14424 ImGuiWindow* window = g.CurrentWindow;
14425 ImGuiStackTool* tool = &g.DebugStackTool;
14426
14427 // Step 0: stack query
14428 // This assumes that the ID was computed with the current ID stack, which tends to be the case for our widget.
14429 if (tool->StackLevel == -1)
14430 {
14431 tool->StackLevel++;
14432 tool->Results.resize(window->IDStack.Size + 1, ImGuiStackLevelInfo());
14433 for (int n = 0; n < window->IDStack.Size + 1; n++)
14434 tool->Results[n].ID = (n < window->IDStack.Size) ? window->IDStack[n] : id;
14435 return;
14436 }
14437
14438 // Step 1+: query for individual level
14439 IM_ASSERT(tool->StackLevel >= 0);
14440 if (tool->StackLevel != window->IDStack.Size)
14441 return;
14442 ImGuiStackLevelInfo* info = &tool->Results[tool->StackLevel];
14443 IM_ASSERT(info->ID == id && info->QueryFrameCount > 0);
14444
14445 switch (data_type)
14446 {
14447 case ImGuiDataType_S32:
14448 ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "%d", (int)(intptr_t)data_id);
14449 break;
14451 ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "%.*s", data_id_end ? (int)((const char*)data_id_end - (const char*)data_id) : (int)strlen((const char*)data_id), (const char*)data_id);
14452 break;
14454 ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "(void*)0x%p", data_id);
14455 break;
14456 case ImGuiDataType_ID:
14457 if (info->Desc[0] != 0) // PushOverrideID() is often used to avoid hashing twice, which would lead to 2 calls to DebugHookIdInfo(). We prioritize the first one.
14458 return;
14459 ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "0x%08X [override]", id);
14460 break;
14461 default:
14462 IM_ASSERT(0);
14463 }
14464 info->QuerySuccess = true;
14465 info->DataType = data_type;
14466}
14467
14468static int StackToolFormatLevelInfo(ImGuiStackTool* tool, int n, bool format_for_ui, char* buf, size_t buf_size)
14469{
14470 ImGuiStackLevelInfo* info = &tool->Results[n];
14471 ImGuiWindow* window = (info->Desc[0] == 0 && n == 0) ? ImGui::FindWindowByID(info->ID) : NULL;
14472 if (window) // Source: window name (because the root ID don't call GetID() and so doesn't get hooked)
14473 return ImFormatString(buf, buf_size, format_for_ui ? "\"%s\" [window]" : "%s", window->Name);
14474 if (info->QuerySuccess) // Source: GetID() hooks (prioritize over ItemInfo() because we frequently use patterns like: PushID(str), Button("") where they both have same id)
14475 return ImFormatString(buf, buf_size, (format_for_ui && info->DataType == ImGuiDataType_String) ? "\"%s\"" : "%s", info->Desc);
14476 if (tool->StackLevel < tool->Results.Size) // Only start using fallback below when all queries are done, so during queries we don't flickering ??? markers.
14477 return (*buf = 0);
14478#ifdef IMGUI_ENABLE_TEST_ENGINE
14479 if (const char* label = ImGuiTestEngine_FindItemDebugLabel(GImGui, info->ID)) // Source: ImGuiTestEngine's ItemInfo()
14480 return ImFormatString(buf, buf_size, format_for_ui ? "??? \"%s\"" : "%s", label);
14481#endif
14482 return ImFormatString(buf, buf_size, "???");
14483}
14484
14485// Stack Tool: Display UI
14487{
14488 ImGuiContext& g = *GImGui;
14491 if (!Begin("Dear ImGui Stack Tool", p_open) || GetCurrentWindow()->BeginCount > 1)
14492 {
14493 End();
14494 return;
14495 }
14496
14497 // Display hovered/active status
14498 ImGuiStackTool* tool = &g.DebugStackTool;
14499 const ImGuiID hovered_id = g.HoveredIdPreviousFrame;
14500 const ImGuiID active_id = g.ActiveId;
14501#ifdef IMGUI_ENABLE_TEST_ENGINE
14502 Text("HoveredId: 0x%08X (\"%s\"), ActiveId: 0x%08X (\"%s\")", hovered_id, hovered_id ? ImGuiTestEngine_FindItemDebugLabel(&g, hovered_id) : "", active_id, active_id ? ImGuiTestEngine_FindItemDebugLabel(&g, active_id) : "");
14503#else
14504 Text("HoveredId: 0x%08X, ActiveId: 0x%08X", hovered_id, active_id);
14505#endif
14506 SameLine();
14507 MetricsHelpMarker("Hover an item with the mouse to display elements of the ID Stack leading to the item's final ID.\nEach level of the stack correspond to a PushID() call.\nAll levels of the stack are hashed together to make the final ID of a widget (ID displayed at the bottom level of the stack).\nRead FAQ entry about the ID stack for details.");
14508
14509 // CTRL+C to copy path
14510 const float time_since_copy = (float)g.Time - tool->CopyToClipboardLastTime;
14511 Checkbox("Ctrl+C: copy path to clipboard", &tool->CopyToClipboardOnCtrlC);
14512 SameLine();
14513 TextColored((time_since_copy >= 0.0f && time_since_copy < 0.75f && ImFmod(time_since_copy, 0.25f) < 0.25f * 0.5f) ? ImVec4(1.f, 1.f, 0.3f, 1.f) : ImVec4(), "*COPIED*");
14515 {
14516 tool->CopyToClipboardLastTime = (float)g.Time;
14517 char* p = g.TempBuffer.Data;
14518 char* p_end = p + g.TempBuffer.Size;
14519 for (int stack_n = 0; stack_n < tool->Results.Size && p + 3 < p_end; stack_n++)
14520 {
14521 *p++ = '/';
14522 char level_desc[256];
14523 StackToolFormatLevelInfo(tool, stack_n, false, level_desc, IM_ARRAYSIZE(level_desc));
14524 for (int n = 0; level_desc[n] && p + 2 < p_end; n++)
14525 {
14526 if (level_desc[n] == '/')
14527 *p++ = '\\';
14528 *p++ = level_desc[n];
14529 }
14530 }
14531 *p = '\0';
14533 }
14534
14535 // Display decorated stack
14536 tool->LastActiveFrame = g.FrameCount;
14537 if (tool->Results.Size > 0 && BeginTable("##table", 3, ImGuiTableFlags_Borders))
14538 {
14539 const float id_width = CalcTextSize("0xDDDDDDDD").x;
14544 for (int n = 0; n < tool->Results.Size; n++)
14545 {
14546 ImGuiStackLevelInfo* info = &tool->Results[n];
14548 Text("0x%08X", (n > 0) ? tool->Results[n - 1].ID : 0);
14550 StackToolFormatLevelInfo(tool, n, true, g.TempBuffer.Data, g.TempBuffer.Size);
14553 Text("0x%08X", info->ID);
14554 if (n == tool->Results.Size - 1)
14556 }
14557 EndTable();
14558 }
14559 End();
14560}
14561
14562#else
14563
14564void ImGui::ShowMetricsWindow(bool*) {}
14567void ImGui::DebugNodeDrawList(ImGuiWindow*, const ImDrawList*, const char*) {}
14570void ImGui::DebugNodeStorage(ImGuiStorage*, const char*) {}
14571void ImGui::DebugNodeTabBar(ImGuiTabBar*, const char*) {}
14572void ImGui::DebugNodeWindow(ImGuiWindow*, const char*) {}
14576
14577void ImGui::DebugLog(const char*, ...) {}
14578void ImGui::DebugLogV(const char*, va_list) {}
14579void ImGui::ShowDebugLogWindow(bool*) {}
14580void ImGui::ShowStackToolWindow(bool*) {}
14581void ImGui::DebugHookIdInfo(ImGuiID, ImGuiDataType, const void*, const void*) {}
14582void ImGui::UpdateDebugToolItemPicker() {}
14583void ImGui::UpdateDebugToolStackQueries() {}
14584
14585#endif // #ifndef IMGUI_DISABLE_DEBUG_TOOLS
14586
14587//-----------------------------------------------------------------------------
14588
14589// Include imgui_user.inl at the end of imgui.cpp to access private data/functions that aren't exposed.
14590// Prefer just including imgui_internal.h from your code rather than using this define. If a declaration is missing from imgui_internal.h add it or request it on the github.
14591#ifdef IMGUI_INCLUDE_IMGUI_USER_INL
14592#include "imgui_user.inl"
14593#endif
14594
14595//-----------------------------------------------------------------------------
14596
14597#endif // #ifndef IMGUI_DISABLE
const char * ImStreolRange(const char *str, const char *str_end)
Definition imgui.cpp:1710
char * ImStrdupcpy(char *dst, size_t *p_dst_size, const char *src)
Definition imgui.cpp:1681
#define va_copy(dest, src)
Definition imgui.cpp:2525
char * ImStrdup(const char *str)
Definition imgui.cpp:1674
ImGuiContext * GImGui
Definition imgui.cpp:1086
int ImFormatStringV(char *buf, size_t buf_size, const char *fmt, va_list args)
Definition imgui.cpp:1808
ImVec2 ImBezierCubicClosestPointCasteljau(const ImVec2 &p1, const ImVec2 &p2, const ImVec2 &p3, const ImVec2 &p4, const ImVec2 &p, float tess_tol)
Definition imgui.cpp:1588
const ImWchar * ImStrbolW(const ImWchar *buf_mid_line, const ImWchar *buf_begin)
Definition imgui.cpp:1716
ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy)
Definition imgui.cpp:10555
void ImTriangleBarycentricCoords(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, const ImVec2 &p, float &out_u, float &out_v, float &out_w)
Definition imgui.cpp:1619
void ImFormatStringToTempBuffer(const char **out_buf, const char **out_buf_end, const char *fmt,...)
Definition imgui.cpp:1824
int ImTextStrToUtf8(char *out_buf, int out_buf_size, const ImWchar *in_text, const ImWchar *in_text_end)
Definition imgui.cpp:2152
int ImStrnicmp(const char *str1, const char *str2, size_t count)
Definition imgui.cpp:1658
int ImStrlenW(const ImWchar *str)
Definition imgui.cpp:1701
const char * ImStrchrRange(const char *str, const char *str_end, char c)
Definition imgui.cpp:1695
int ImFormatString(char *buf, size_t buf_size, const char *fmt,...)
Definition imgui.cpp:1790
ImVec2 ImLineClosestPoint(const ImVec2 &a, const ImVec2 &b, const ImVec2 &p)
Definition imgui.cpp:1598
void ImStrTrimBlanks(char *buf)
Definition imgui.cpp:1746
void ImFormatStringToTempBufferV(const char **out_buf, const char **out_buf_end, const char *fmt, va_list args)
Definition imgui.cpp:1844
#define MAP_LEGACY_NAV_INPUT_TO_KEY2(_KEY, _NAV1, _NAV2)
IM_MSVC_RUNTIME_CHECKS_RESTORE IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b)
Definition imgui.cpp:2188
const char * ImStrSkipBlank(const char *str)
Definition imgui.cpp:1761
const char * ImTextCharToUtf8(char out_buf[5], unsigned int c)
Definition imgui.cpp:2129
bool ImTriangleContainsPoint(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, const ImVec2 &p)
Definition imgui.cpp:1611
ImU64 ImFileWrite(const void *data, ImU64 sz, ImU64 count, ImFileHandle f)
Definition imgui.cpp:1959
#define IMGUI_DEBUG_NAV_SCORING
Definition imgui.cpp:973
int ImTextCountUtf8BytesFromStr(const ImWchar *in_text, const ImWchar *in_text_end)
Definition imgui.cpp:2168
ImU64 ImFileRead(void *data, ImU64 sz, ImU64 count, ImFileHandle f)
Definition imgui.cpp:1958
ImGuiID ImHashStr(const char *data_p, size_t data_size, ImGuiID seed)
Definition imgui.cpp:1903
#define MAP_LEGACY_NAV_INPUT_TO_KEY1(_KEY, _NAV1)
IM_MSVC_RUNTIME_CHECKS_OFF int ImTextCharFromUtf8(unsigned int *out_char, const char *in_text, const char *in_text_end)
Definition imgui.cpp:2013
int ImTextCountCharsFromUtf8(const char *in_text, const char *in_text_end)
Definition imgui.cpp:2081
bool ImFileClose(ImFileHandle f)
Definition imgui.cpp:1956
void * ImFileLoadToMemory(const char *filename, const char *mode, size_t *out_file_size, int padding_bytes)
Definition imgui.cpp:1965
const char * ImStristr(const char *haystack, const char *haystack_end, const char *needle, const char *needle_end)
Definition imgui.cpp:1723
ImVec2 ImBezierCubicClosestPoint(const ImVec2 &p1, const ImVec2 &p2, const ImVec2 &p3, const ImVec2 &p4, const ImVec2 &p, int num_segments)
Definition imgui.cpp:1530
ImGuiID ImHashData(const void *data_p, size_t data_size, ImGuiID seed)
Definition imgui.cpp:1887
ImU64 ImFileGetSize(ImFileHandle f)
Definition imgui.cpp:1957
int ImStricmp(const char *str1, const char *str2)
Definition imgui.cpp:1651
int ImTextCountUtf8BytesFromChar(const char *in_text, const char *in_text_end)
Definition imgui.cpp:2137
ImFileHandle ImFileOpen(const char *filename, const char *mode)
Definition imgui.cpp:1938
int ImTextStrFromUtf8(ImWchar *buf, int buf_size, const char *in_text, const char *in_text_end, const char **in_text_remaining)
Definition imgui.cpp:2065
void ImStrncpy(char *dst, const char *src, size_t count)
Definition imgui.cpp:1665
ImVec2 ImTriangleClosestPoint(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, const ImVec2 &p)
Definition imgui.cpp:1630
unsigned short ImWchar16
Definition imgui.h:236
@ ImGuiFocusedFlags_AnyWindow
Definition imgui.h:1263
@ ImGuiFocusedFlags_NoPopupHierarchy
Definition imgui.h:1264
int ImGuiTreeNodeFlags
Definition imgui.h:205
int ImGuiKeyChord
Definition imgui.h:196
#define IM_COL32_WHITE
Definition imgui.h:2375
@ ImGuiDragDropFlags_AcceptBeforeDelivery
Definition imgui.h:1307
@ ImGuiDragDropFlags_SourceNoPreviewTooltip
Definition imgui.h:1300
@ ImGuiDragDropFlags_SourceAllowNullID
Definition imgui.h:1303
@ ImGuiDragDropFlags_None
Definition imgui.h:1298
@ ImGuiDragDropFlags_SourceExtern
Definition imgui.h:1304
@ ImGuiDragDropFlags_AcceptNoDrawDefaultRect
Definition imgui.h:1308
@ ImGuiDragDropFlags_SourceNoDisableHover
Definition imgui.h:1301
@ ImGuiDragDropFlags_SourceAutoExpirePayload
Definition imgui.h:1305
@ ImGuiDragDropFlags_AcceptNoPreviewTooltip
Definition imgui.h:1309
int ImGuiWindowFlags
Definition imgui.h:207
@ ImGuiDataType_Float
Definition imgui.h:1328
@ ImGuiDataType_S32
Definition imgui.h:1324
unsigned int ImU32
Definition imgui.h:230
#define IM_COL32(R, G, B, A)
Definition imgui.h:2374
@ ImGuiHoveredFlags_DelayShort
Definition imgui.h:1291
@ ImGuiHoveredFlags_None
Definition imgui.h:1274
@ ImGuiHoveredFlags_AllowWhenBlockedByActiveItem
Definition imgui.h:1282
@ ImGuiHoveredFlags_AllowWhenBlockedByPopup
Definition imgui.h:1280
@ ImGuiHoveredFlags_NoNavOverride
Definition imgui.h:1285
@ ImGuiHoveredFlags_NoPopupHierarchy
Definition imgui.h:1278
@ ImGuiHoveredFlags_NoSharedDelay
Definition imgui.h:1292
@ ImGuiHoveredFlags_ChildWindows
Definition imgui.h:1275
@ ImGuiHoveredFlags_RootWindow
Definition imgui.h:1276
@ ImGuiHoveredFlags_AnyWindow
Definition imgui.h:1277
@ ImGuiHoveredFlags_AllowWhenOverlapped
Definition imgui.h:1283
@ ImGuiHoveredFlags_AllowWhenDisabled
Definition imgui.h:1284
@ ImGuiHoveredFlags_DelayNormal
Definition imgui.h:1290
unsigned int ImGuiID
Definition imgui.h:224
#define IM_COL32_G_SHIFT
Definition imgui.h:2368
@ ImGuiConfigFlags_NoMouse
Definition imgui.h:1502
@ ImGuiConfigFlags_NavEnableSetMousePos
Definition imgui.h:1500
@ ImGuiConfigFlags_NavEnableGamepad
Definition imgui.h:1499
@ ImGuiConfigFlags_None
Definition imgui.h:1497
@ ImGuiConfigFlags_NavEnableKeyboard
Definition imgui.h:1498
@ ImGuiConfigFlags_NavNoCaptureKeyboard
Definition imgui.h:1501
void *(* ImGuiMemAllocFunc)(size_t sz, void *user_data)
Definition imgui.h:247
int ImDrawListFlags
Definition imgui.h:185
int ImGuiCol
Definition imgui.h:170
void(* ImGuiSizeCallback)(ImGuiSizeCallbackData *data)
Definition imgui.h:246
ImWchar16 ImWchar
Definition imgui.h:241
#define IM_COL32_R_SHIFT
Definition imgui.h:2367
@ ImDrawListFlags_None
Definition imgui.h:2521
@ ImDrawListFlags_AntiAliasedLinesUseTex
Definition imgui.h:2523
@ ImDrawListFlags_AntiAliasedFill
Definition imgui.h:2524
@ ImDrawListFlags_AntiAliasedLines
Definition imgui.h:2522
@ ImDrawListFlags_AllowVtxOffset
Definition imgui.h:2525
#define IM_UNUSED(_VAR)
Definition imgui.h:86
@ ImGuiBackendFlags_HasGamepad
Definition imgui.h:1514
@ ImGuiBackendFlags_HasMouseCursors
Definition imgui.h:1515
@ ImGuiBackendFlags_HasSetMousePos
Definition imgui.h:1516
@ ImGuiBackendFlags_RendererHasVtxOffset
Definition imgui.h:1517
@ ImGuiBackendFlags_None
Definition imgui.h:1513
@ ImGuiMouseCursor_None
Definition imgui.h:1709
@ ImGuiMouseCursor_ResizeNWSE
Definition imgui.h:1716
@ ImGuiMouseCursor_Hand
Definition imgui.h:1717
@ ImGuiMouseCursor_ResizeEW
Definition imgui.h:1714
@ ImGuiMouseCursor_COUNT
Definition imgui.h:1719
@ ImGuiMouseCursor_ResizeNS
Definition imgui.h:1713
@ ImGuiMouseCursor_ResizeNESW
Definition imgui.h:1715
@ ImGuiMouseCursor_Arrow
Definition imgui.h:1710
#define IM_OFFSETOF(_TYPE, _MEMBER)
Definition imgui.h:87
signed char ImS8
Definition imgui.h:225
void * ImTextureID
Definition imgui.h:213
unsigned char ImU8
Definition imgui.h:226
int ImGuiHoveredFlags
Definition imgui.h:194
void IM_DELETE(T *p)
Definition imgui.h:1751
#define IM_ALLOC(_SIZE)
Definition imgui.h:1747
#define IM_PLACEMENT_NEW(_PTR)
Definition imgui.h:1749
#define IMGUI_API
Definition imgui.h:74
int ImGuiFocusedFlags
Definition imgui.h:193
@ ImGuiTableColumnFlags_WidthFixed
Definition imgui.h:1205
@ ImGuiTableColumnFlags_WidthStretch
Definition imgui.h:1204
int ImGuiDataType
Definition imgui.h:172
int ImGuiDragDropFlags
Definition imgui.h:192
@ ImGuiPopupFlags_MouseButtonMask_
Definition imgui.h:1060
@ ImGuiPopupFlags_AnyPopupLevel
Definition imgui.h:1065
@ ImGuiPopupFlags_NoOpenOverExistingPopup
Definition imgui.h:1062
@ ImGuiPopupFlags_AnyPopupId
Definition imgui.h:1064
@ ImGuiPopupFlags_NoOpenOverItems
Definition imgui.h:1063
@ ImGuiPopupFlags_None
Definition imgui.h:1056
#define IM_NEW(_TYPE)
Definition imgui.h:1750
@ ImGuiStyleVar_ChildRounding
Definition imgui.h:1596
@ ImGuiStyleVar_WindowPadding
Definition imgui.h:1591
@ ImGuiStyleVar_ChildBorderSize
Definition imgui.h:1597
@ ImGuiStyleVar_COUNT
Definition imgui.h:1617
unsigned long long ImU64
Definition imgui.h:232
@ ImGuiInputTextFlags_ReadOnly
Definition imgui.h:1010
#define IM_COL32_B_SHIFT
Definition imgui.h:2369
@ ImGuiTableBgTarget_CellBg
Definition imgui.h:1254
unsigned short ImU16
Definition imgui.h:228
#define IM_MSVC_RUNTIME_CHECKS_OFF
Definition imgui.h:107
@ ImFontAtlasFlags_NoBakedLines
Definition imgui.h:2761
#define IM_COL32_A_MASK
Definition imgui.h:2371
int ImGuiDir
Definition imgui.h:173
@ ImGuiCol_BorderShadow
Definition imgui.h:1529
@ ImGuiCol_TextDisabled
Definition imgui.h:1524
@ ImGuiCol_FrameBgHovered
Definition imgui.h:1531
@ ImGuiCol_HeaderActive
Definition imgui.h:1549
@ ImGuiCol_TitleBgCollapsed
Definition imgui.h:1535
@ ImGuiCol_PlotHistogramHovered
Definition imgui.h:1564
@ ImGuiCol_ScrollbarGrab
Definition imgui.h:1538
@ ImGuiCol_TextSelectedBg
Definition imgui.h:1570
@ ImGuiCol_MenuBarBg
Definition imgui.h:1536
@ ImGuiCol_PlotHistogram
Definition imgui.h:1563
@ ImGuiCol_Header
Definition imgui.h:1547
@ ImGuiCol_TabHovered
Definition imgui.h:1557
@ ImGuiCol_HeaderHovered
Definition imgui.h:1548
@ ImGuiCol_FrameBg
Definition imgui.h:1530
@ ImGuiCol_TabUnfocused
Definition imgui.h:1559
@ ImGuiCol_ModalWindowDimBg
Definition imgui.h:1575
@ ImGuiCol_DragDropTarget
Definition imgui.h:1571
@ ImGuiCol_Button
Definition imgui.h:1544
@ ImGuiCol_TabUnfocusedActive
Definition imgui.h:1560
@ ImGuiCol_ButtonHovered
Definition imgui.h:1545
@ ImGuiCol_ButtonActive
Definition imgui.h:1546
@ ImGuiCol_SeparatorActive
Definition imgui.h:1552
@ ImGuiCol_TableRowBg
Definition imgui.h:1568
@ ImGuiCol_Border
Definition imgui.h:1528
@ ImGuiCol_FrameBgActive
Definition imgui.h:1532
@ ImGuiCol_ScrollbarGrabActive
Definition imgui.h:1540
@ ImGuiCol_WindowBg
Definition imgui.h:1525
@ ImGuiCol_TableHeaderBg
Definition imgui.h:1565
@ ImGuiCol_TitleBgActive
Definition imgui.h:1534
@ ImGuiCol_Text
Definition imgui.h:1523
@ ImGuiCol_ResizeGripActive
Definition imgui.h:1555
@ ImGuiCol_TableRowBgAlt
Definition imgui.h:1569
@ ImGuiCol_ChildBg
Definition imgui.h:1526
@ ImGuiCol_PopupBg
Definition imgui.h:1527
@ ImGuiCol_Tab
Definition imgui.h:1556
@ ImGuiCol_ScrollbarBg
Definition imgui.h:1537
@ ImGuiCol_CheckMark
Definition imgui.h:1541
@ ImGuiCol_TabActive
Definition imgui.h:1558
@ ImGuiCol_TableBorderLight
Definition imgui.h:1567
@ ImGuiCol_ScrollbarGrabHovered
Definition imgui.h:1539
@ ImGuiCol_TitleBg
Definition imgui.h:1533
@ ImGuiCol_PlotLines
Definition imgui.h:1561
@ ImGuiCol_ResizeGripHovered
Definition imgui.h:1554
@ ImGuiCol_NavWindowingHighlight
Definition imgui.h:1573
@ ImGuiCol_TableBorderStrong
Definition imgui.h:1566
@ ImGuiCol_SliderGrabActive
Definition imgui.h:1543
@ ImGuiCol_SliderGrab
Definition imgui.h:1542
@ ImGuiCol_SeparatorHovered
Definition imgui.h:1551
@ ImGuiCol_ResizeGrip
Definition imgui.h:1553
@ ImGuiCol_Separator
Definition imgui.h:1550
@ ImGuiCol_NavHighlight
Definition imgui.h:1572
@ ImGuiCol_NavWindowingDimBg
Definition imgui.h:1574
@ ImGuiCol_PlotLinesHovered
Definition imgui.h:1562
int ImGuiMouseCursor
Definition imgui.h:175
#define IM_UNICODE_CODEPOINT_INVALID
Definition imgui.h:2171
ImGuiKey
Definition imgui.h:1358
@ ImGuiKey_GamepadFaceRight
Definition imgui.h:1416
@ ImGuiKey_PageUp
Definition imgui.h:1366
@ ImGuiMod_Mask_
Definition imgui.h:1460
@ ImGuiKey_S
Definition imgui.h:1381
@ ImGuiKey_RightArrow
Definition imgui.h:1363
@ ImGuiKey_Escape
Definition imgui.h:1375
@ ImGuiKey_W
Definition imgui.h:1382
@ ImGuiKey_LeftShift
Definition imgui.h:1376
@ ImGuiKey_GamepadLStickDown
Definition imgui.h:1432
@ ImGuiKey_DownArrow
Definition imgui.h:1365
@ ImGuiKey_GamepadFaceUp
Definition imgui.h:1417
@ ImGuiKey_Home
Definition imgui.h:1368
@ ImGuiKey_NamedKey_BEGIN
Definition imgui.h:1465
@ ImGuiKey_Z
Definition imgui.h:1382
@ ImGuiMod_Shift
Definition imgui.h:1456
@ ImGuiMod_Alt
Definition imgui.h:1457
@ ImGuiMod_Ctrl
Definition imgui.h:1455
@ ImGuiKey_GamepadDpadDown
Definition imgui.h:1422
@ ImGuiKey_None
Definition imgui.h:1360
@ ImGuiKey_MouseWheelX
Definition imgui.h:1440
@ ImGuiKey_Tab
Definition imgui.h:1361
@ ImGuiKey_GamepadR1
Definition imgui.h:1424
@ ImGuiMod_Super
Definition imgui.h:1458
@ ImGuiMod_Shortcut
Definition imgui.h:1459
@ ImGuiKey_A
Definition imgui.h:1380
@ ImGuiKey_C
Definition imgui.h:1380
@ ImGuiKey_PageDown
Definition imgui.h:1367
@ ImGuiKey_F
Definition imgui.h:1380
@ ImGuiKey_R
Definition imgui.h:1381
@ ImGuiKey_KeysData_OFFSET
Definition imgui.h:1473
@ ImGuiMod_None
Definition imgui.h:1454
@ ImGuiKey_X
Definition imgui.h:1382
@ ImGuiKey_NamedKey_END
Definition imgui.h:1466
@ ImGuiKey_GamepadL1
Definition imgui.h:1423
@ ImGuiKey_GamepadLStickUp
Definition imgui.h:1431
@ ImGuiKey_GamepadFaceDown
Definition imgui.h:1418
@ ImGuiKey_E
Definition imgui.h:1380
@ ImGuiKey_UpArrow
Definition imgui.h:1364
@ ImGuiKey_GamepadLStickLeft
Definition imgui.h:1429
@ ImGuiKey_Space
Definition imgui.h:1373
@ ImGuiKey_LeftArrow
Definition imgui.h:1362
@ ImGuiKey_Q
Definition imgui.h:1381
@ ImGuiKey_MouseWheelY
Definition imgui.h:1440
@ ImGuiKey_End
Definition imgui.h:1369
@ ImGuiKey_GamepadDpadUp
Definition imgui.h:1421
@ ImGuiKey_GamepadDpadRight
Definition imgui.h:1420
@ ImGuiKey_GamepadDpadLeft
Definition imgui.h:1419
@ ImGuiKey_NamedKey_COUNT
Definition imgui.h:1467
@ ImGuiKey_CapsLock
Definition imgui.h:1396
@ ImGuiKey_V
Definition imgui.h:1382
@ ImGuiKey_Enter
Definition imgui.h:1374
@ ImGuiKey_GamepadFaceLeft
Definition imgui.h:1415
@ ImGuiKey_KeysData_SIZE
Definition imgui.h:1472
@ ImGuiKey_D
Definition imgui.h:1380
@ ImGuiKey_COUNT
Definition imgui.h:1444
@ ImGuiKey_GamepadLStickRight
Definition imgui.h:1430
@ ImGuiMouseButton_COUNT
Definition imgui.h:1702
@ ImGuiMouseButton_Left
Definition imgui.h:1699
#define IMGUI_VERSION
Definition imgui.h:25
@ ImGuiTreeNodeFlags_Selected
Definition imgui.h:1028
@ ImGuiTreeNodeFlags_None
Definition imgui.h:1027
@ ImGuiNavInput_FocusPrev
Definition imgui.h:1489
@ ImGuiNavInput_LStickRight
Definition imgui.h:1489
@ ImGuiNavInput_Menu
Definition imgui.h:1488
@ ImGuiNavInput_LStickUp
Definition imgui.h:1489
@ ImGuiNavInput_TweakFast
Definition imgui.h:1489
@ ImGuiNavInput_DpadLeft
Definition imgui.h:1488
@ ImGuiNavInput_DpadRight
Definition imgui.h:1488
@ ImGuiNavInput_FocusNext
Definition imgui.h:1489
@ ImGuiNavInput_Activate
Definition imgui.h:1488
@ ImGuiNavInput_Cancel
Definition imgui.h:1488
@ ImGuiNavInput_DpadDown
Definition imgui.h:1488
@ ImGuiNavInput_LStickLeft
Definition imgui.h:1489
@ ImGuiNavInput_LStickDown
Definition imgui.h:1489
@ ImGuiNavInput_TweakSlow
Definition imgui.h:1489
@ ImGuiNavInput_DpadUp
Definition imgui.h:1488
@ ImGuiNavInput_Input
Definition imgui.h:1488
int ImGuiMouseButton
Definition imgui.h:174
#define IM_FREE(_PTR)
Definition imgui.h:1748
int ImGuiStyleVar
Definition imgui.h:177
#define IM_ASSERT(_EXPR)
Definition imgui.h:83
#define IM_MSVC_RUNTIME_CHECKS_RESTORE
Definition imgui.h:108
@ ImGuiViewportFlags_OwnedByApp
Definition imgui.h:2947
@ ImGuiViewportFlags_IsPlatformWindow
Definition imgui.h:2945
@ ImGuiViewportFlags_IsPlatformMonitor
Definition imgui.h:2946
@ ImGuiWindowFlags_NoInputs
Definition imgui.h:980
@ ImGuiWindowFlags_NoBackground
Definition imgui.h:965
@ ImGuiWindowFlags_NoNavInputs
Definition imgui.h:975
@ ImGuiWindowFlags_AlwaysUseWindowPadding
Definition imgui.h:974
@ ImGuiWindowFlags_AlwaysAutoResize
Definition imgui.h:964
@ ImGuiWindowFlags_MenuBar
Definition imgui.h:968
@ ImGuiWindowFlags_HorizontalScrollbar
Definition imgui.h:969
@ ImGuiWindowFlags_Tooltip
Definition imgui.h:985
@ ImGuiWindowFlags_NoTitleBar
Definition imgui.h:958
@ ImGuiWindowFlags_NoNavFocus
Definition imgui.h:976
@ ImGuiWindowFlags_AlwaysVerticalScrollbar
Definition imgui.h:972
@ ImGuiWindowFlags_NoFocusOnAppearing
Definition imgui.h:970
@ ImGuiWindowFlags_NoCollapse
Definition imgui.h:963
@ ImGuiWindowFlags_NoScrollWithMouse
Definition imgui.h:962
@ ImGuiWindowFlags_Modal
Definition imgui.h:987
@ ImGuiWindowFlags_NoMouseInputs
Definition imgui.h:967
@ ImGuiWindowFlags_UnsavedDocument
Definition imgui.h:977
@ ImGuiWindowFlags_NoSavedSettings
Definition imgui.h:966
@ ImGuiWindowFlags_NoBringToFrontOnFocus
Definition imgui.h:971
@ ImGuiWindowFlags_Popup
Definition imgui.h:986
@ ImGuiWindowFlags_ChildMenu
Definition imgui.h:988
@ ImGuiWindowFlags_AlwaysHorizontalScrollbar
Definition imgui.h:973
@ ImGuiWindowFlags_NavFlattened
Definition imgui.h:983
@ ImGuiWindowFlags_NoMove
Definition imgui.h:960
@ ImGuiWindowFlags_ChildWindow
Definition imgui.h:984
@ ImGuiWindowFlags_NoResize
Definition imgui.h:959
@ ImGuiWindowFlags_NoScrollbar
Definition imgui.h:961
@ ImGuiWindowFlags_None
Definition imgui.h:957
@ ImGuiCond_FirstUseEver
Definition imgui.h:1730
@ ImGuiCond_Always
Definition imgui.h:1728
@ ImGuiCond_Once
Definition imgui.h:1729
@ ImGuiCond_Appearing
Definition imgui.h:1731
@ ImGuiDir_Down
Definition imgui.h:1340
@ ImGuiDir_Right
Definition imgui.h:1338
@ ImGuiDir_COUNT
Definition imgui.h:1341
@ ImGuiDir_Up
Definition imgui.h:1339
@ ImGuiDir_None
Definition imgui.h:1336
@ ImGuiDir_Left
Definition imgui.h:1337
void(* ImGuiMemFreeFunc)(void *ptr, void *user_data)
Definition imgui.h:248
@ ImGuiTableFlags_Borders
Definition imgui.h:1166
@ ImGuiTableFlags_RowBg
Definition imgui.h:1157
@ ImGuiTableFlags_SizingFixedFit
Definition imgui.h:1170
#define IM_ARRAYSIZE(_ARR)
Definition imgui.h:85
int ImGuiCond
Definition imgui.h:171
#define IM_UNICODE_CODEPOINT_MAX
Definition imgui.h:2175
int ImGuiPopupFlags
Definition imgui.h:197
@ ImDrawFlags_None
Definition imgui.h:2501
@ ImDrawFlags_RoundCornersBottom
Definition imgui.h:2509
@ ImDrawFlags_Closed
Definition imgui.h:2502
@ ImDrawFlags_RoundCornersTop
Definition imgui.h:2508
#define IM_COL32_BLACK
Definition imgui.h:2376
#define IM_COL32_A_SHIFT
Definition imgui.h:2370
unsigned short ImDrawIdx
Definition imgui.h:220
ImVec2 ImBezierCubicCalc(const ImVec2 &p1, const ImVec2 &p2, const ImVec2 &p3, const ImVec2 &p4, float t)
ImGuiContextHookType
@ ImGuiContextHookType_PendingRemoval_
@ ImGuiContextHookType_RenderPost
@ ImGuiContextHookType_NewFramePost
@ ImGuiContextHookType_RenderPre
@ ImGuiContextHookType_EndFramePre
@ ImGuiContextHookType_NewFramePre
@ ImGuiContextHookType_EndFramePost
@ ImGuiContextHookType_Shutdown
#define IM_F32_TO_INT8_SAT(_VAL)
#define IMGUI_DEBUG_PRINTF(_FMT,...)
@ ImGuiScrollFlags_KeepVisibleEdgeY
@ ImGuiScrollFlags_MaskX_
@ ImGuiScrollFlags_NoScrollParent
@ ImGuiScrollFlags_AlwaysCenterX
@ ImGuiScrollFlags_KeepVisibleCenterX
@ ImGuiScrollFlags_AlwaysCenterY
@ ImGuiScrollFlags_MaskY_
@ ImGuiScrollFlags_KeepVisibleEdgeX
@ ImGuiScrollFlags_KeepVisibleCenterY
@ ImGuiScrollFlags_None
#define IM_NEWLINE
#define ImGuiKey_NavGamepadTweakFast
#define IMGUI_CDECL
#define ImGuiKey_Gamepad_END
int ImGuiScrollFlags
@ ImGuiLocKey_WindowingMainMenuBar
@ ImGuiLocKey_TableSizeAllDefault
@ ImGuiLocKey_TableResetOrder
@ ImGuiLocKey_WindowingUntitled
@ ImGuiLocKey_WindowingPopup
@ ImGuiLocKey_TableSizeAllFit
@ ImGuiLocKey_TableSizeOne
ImGuiAxis
@ ImGuiAxis_X
@ ImGuiAxis_Y
@ ImGuiButtonFlags_FlattenChildren
@ ImGuiButtonFlags_NoNavFocus
#define IM_DEBUG_BREAK()
#define IM_ASSERT_USER_ERROR(_EXP, _MSG)
@ ImGuiNavHighlightFlags_NoRounding
@ ImGuiNavHighlightFlags_TypeThin
@ ImGuiNavHighlightFlags_AlwaysDraw
@ ImGuiNavHighlightFlags_TypeDefault
@ ImGuiDebugLogFlags_EventClipper
@ ImGuiDebugLogFlags_OutputToTTY
@ ImGuiDebugLogFlags_EventFocus
@ ImGuiDebugLogFlags_EventActiveId
@ ImGuiDebugLogFlags_EventNav
@ ImGuiDebugLogFlags_EventIO
@ ImGuiDebugLogFlags_EventMask_
@ ImGuiDebugLogFlags_EventPopup
FILE * ImFileHandle
#define ImGuiKey_NavGamepadCancel
#define IMGUI_DEBUG_LOG_CLIPPER(...)
@ ImGuiItemFlags_Disabled
@ ImGuiItemFlags_NoTabStop
@ ImGuiItemFlags_None
@ ImGuiItemFlags_NoNavDefaultFocus
@ ImGuiItemFlags_ButtonRepeat
@ ImGuiItemFlags_Inputable
@ ImGuiItemFlags_NoNav
@ ImGuiItemFlags_NoWindowHoverableCheck
IMGUI_API char * ImStrdup(const char *str)
Definition imgui.cpp:1674
#define ImGuiKey_NavGamepadActivate
#define IMGUI_DEBUG_LOG_ACTIVEID(...)
@ ImGuiTooltipFlags_None
@ ImGuiTooltipFlags_OverridePreviousTooltip
@ ImGuiItemStatusFlags_ToggledSelection
@ ImGuiItemStatusFlags_HasDisplayRect
@ ImGuiItemStatusFlags_HoveredRect
@ ImGuiItemStatusFlags_Deactivated
@ ImGuiItemStatusFlags_Edited
@ ImGuiItemStatusFlags_HasDeactivated
@ ImGuiItemStatusFlags_HoveredWindow
@ ImGuiItemStatusFlags_None
@ ImGuiItemStatusFlags_Visible
@ ImGuiItemStatusFlags_ToggledOpen
#define ImGuiKeyOwner_Any
#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS)
IMGUI_API ImGuiID ImHashStr(const char *data, size_t data_size=0, ImGuiID seed=0)
Definition imgui.cpp:1903
#define ImGuiKey_NavGamepadMenu
@ ImGuiInputFlags_None
@ ImGuiInputFlags_RepeatRateMask_
@ ImGuiInputFlags_CondActive
@ ImGuiInputFlags_RepeatRateNavTweak
@ ImGuiInputFlags_RouteMask_
@ ImGuiInputFlags_CondDefault_
@ ImGuiInputFlags_SupportedByShortcut
@ ImGuiInputFlags_SupportedBySetItemKeyOwner
@ ImGuiInputFlags_RepeatRateDefault
@ ImGuiInputFlags_LockUntilRelease
@ ImGuiInputFlags_RouteGlobal
@ ImGuiInputFlags_RouteGlobalLow
@ ImGuiInputFlags_CondHovered
@ ImGuiInputFlags_LockThisFrame
@ ImGuiInputFlags_RouteFocused
@ ImGuiInputFlags_CondMask_
@ ImGuiInputFlags_SupportedByIsKeyPressed
@ ImGuiInputFlags_Repeat
@ ImGuiInputFlags_RouteGlobalHigh
@ ImGuiInputFlags_RouteAlways
@ ImGuiInputFlags_RouteUnlessBgFocused
@ ImGuiInputFlags_RepeatRateNavMove
@ ImGuiInputFlags_SupportedBySetKeyOwner
int ImGuiItemStatusFlags
#define ImGuiKeyOwner_None
ImGuiInputEventType
@ ImGuiInputEventType_Focus
@ ImGuiInputEventType_Text
@ ImGuiInputEventType_MouseWheel
@ ImGuiInputEventType_Key
@ ImGuiInputEventType_MousePos
@ ImGuiInputEventType_MouseButton
int ImGuiNavHighlightFlags
#define IMGUI_TEST_ENGINE_ITEM_ADD(_BB, _ID)
ImGuiInputSource
@ ImGuiInputSource_Mouse
@ ImGuiInputSource_Gamepad
@ ImGuiInputSource_COUNT
@ ImGuiInputSource_Keyboard
@ ImGuiInputSource_Nav
#define ImGuiKey_NavGamepadInput
#define ImGuiKey_LegacyNativeKey_END
ImGuiPopupPositionPolicy
@ ImGuiPopupPositionPolicy_ComboBox
@ ImGuiPopupPositionPolicy_Tooltip
@ ImGuiPopupPositionPolicy_Default
#define IMGUI_DEBUG_LOG_FOCUS(...)
ImS16 ImGuiKeyRoutingIndex
#define ImGuiKey_Keyboard_END
int ImGuiInputFlags
#define ImFabs(X)
#define IMGUI_DEBUG_LOG_NAV(...)
#define ImFmod(X, Y)
@ ImGuiNextItemDataFlags_None
@ ImGuiNextItemDataFlags_HasWidth
#define IM_STATIC_ASSERT(_COND)
#define ImGuiKey_LegacyNativeKey_BEGIN
#define IM_PI
@ ImGuiNextWindowDataFlags_HasSizeConstraint
@ ImGuiNextWindowDataFlags_HasSize
@ ImGuiNextWindowDataFlags_HasFocus
@ ImGuiNextWindowDataFlags_HasBgAlpha
@ ImGuiNextWindowDataFlags_HasContentSize
@ ImGuiNextWindowDataFlags_HasScroll
@ ImGuiNextWindowDataFlags_HasCollapsed
@ ImGuiNextWindowDataFlags_HasPos
@ ImGuiLayoutType_Vertical
@ ImGuiLayoutType_Horizontal
int ImGuiItemFlags
#define IMGUI_DEBUG_LOG_POPUP(...)
ImGuiLogType
@ ImGuiLogType_TTY
@ ImGuiLogType_None
@ ImGuiLogType_Clipboard
@ ImGuiLogType_File
@ ImGuiLogType_Buffer
@ ImGuiActivateFlags_PreferInput
@ ImGuiActivateFlags_TryToPreserveState
@ ImGuiActivateFlags_None
@ ImGuiActivateFlags_PreferTweak
#define IM_ROUND(_VAL)
int ImGuiTooltipFlags
@ ImGuiNavMoveFlags_Forwarded
@ ImGuiNavMoveFlags_WrapY
@ ImGuiNavMoveFlags_Tabbing
@ ImGuiNavMoveFlags_AlsoScoreVisibleSet
@ ImGuiNavMoveFlags_DontSetNavHighlight
@ ImGuiNavMoveFlags_AllowCurrentNavId
@ ImGuiNavMoveFlags_DebugNoResult
@ ImGuiNavMoveFlags_WrapX
@ ImGuiNavMoveFlags_LoopY
@ ImGuiNavMoveFlags_None
@ ImGuiNavMoveFlags_ScrollToEdgeY
@ ImGuiNavMoveFlags_LoopX
@ ImGuiNavMoveFlags_FocusApi
@ ImGuiNavMoveFlags_Activate
#define IM_FLOOR(_VAL)
#define ImGuiKey_NavGamepadTweakSlow
float ImTriangleArea(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c)
#define IM_MSVC_WARNING_SUPPRESS(XXXX)
#define IMGUI_DEBUG_LOG_IO(...)
#define ImGuiKey_Gamepad_BEGIN
void(* ImGuiErrorLogCallback)(void *user_data, const char *fmt,...)
#define ImGuiKey_Keyboard_BEGIN
#define ImSqrt(X)
IMGUI_API ImGuiID ImHashData(const void *data, size_t data_size, ImGuiID seed=0)
Definition imgui.cpp:1887
@ ImGuiDataType_ID
@ ImGuiDataType_String
@ ImGuiDataType_Pointer
ImGuiNavLayer
@ ImGuiNavLayer_Menu
@ ImGuiNavLayer_COUNT
@ ImGuiNavLayer_Main
int ImGuiNavMoveFlags
IMGUI_API void SetCursorPosY(float local_y)
Definition imgui.cpp:9373
IMGUI_API void ClosePopupsOverWindow(ImGuiWindow *ref_window, bool restore_focus_to_window_under_popup)
Definition imgui.cpp:10089
IMGUI_API int GetFrameCount()
Definition imgui.cpp:4098
IMGUI_API float GetCursorPosX()
Definition imgui.cpp:9345
IMGUI_API void RenderTextEllipsis(ImDrawList *draw_list, const ImVec2 &pos_min, const ImVec2 &pos_max, float clip_max_x, float ellipsis_max_x, const char *text, const char *text_end, const ImVec2 *text_size_if_known)
Definition imgui.cpp:3276
IMGUI_API void EndDragDropSource()
Definition imgui.cpp:12084
IMGUI_API ImGuiKey GetKeyIndex(ImGuiKey key)
Definition imgui.cpp:7707
IMGUI_API bool InputTextMultiline(const char *label, char *buf, size_t buf_size, const ImVec2 &size=ImVec2(0, 0), ImGuiInputTextFlags flags=0, ImGuiInputTextCallback callback=NULL, void *user_data=NULL)
IMGUI_API bool BeginTable(const char *str_id, int column, ImGuiTableFlags flags=0, const ImVec2 &outer_size=ImVec2(0.0f, 0.0f), float inner_width=0.0f)
IMGUI_API bool IsAnyItemHovered()
Definition imgui.cpp:5142
ImGuiWindow * GetCurrentWindowRead()
const char * LocalizeGetMsg(ImGuiLocKey key)
IMGUI_API bool BeginChildFrame(ImGuiID id, const ImVec2 &size, ImGuiWindowFlags flags=0)
Definition imgui.cpp:5328
IMGUI_API void EndGroup()
Definition imgui.cpp:9586
IMGUI_API bool BeginTooltip()
Definition imgui.cpp:9895
IMGUI_API void SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags status_flags, const ImRect &item_rect)
Definition imgui.cpp:4011
ImRect WindowRectAbsToRel(ImGuiWindow *window, const ImRect &r)
IMGUI_API void ColorConvertHSVtoRGB(float h, float s, float v, float &out_r, float &out_g, float &out_b)
Definition imgui.cpp:2241
IMGUI_API void SetScrollX(float scroll_x)
Definition imgui.cpp:9815
IMGUI_API void PopTextWrapPos()
Definition imgui.cpp:7049
IMGUI_API ImVec2 GetContentRegionMax()
Definition imgui.cpp:9516
IMGUI_API void ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup)
Definition imgui.cpp:10148
IMGUI_API void TableHeadersRow()
IMGUI_API ImVec2 ScrollToRectEx(ImGuiWindow *window, const ImRect &rect, ImGuiScrollFlags flags=0)
Definition imgui.cpp:9705
IMGUI_API bool IsAnyMouseDown()
Definition imgui.cpp:8205
IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul=1.0f)
Definition imgui.cpp:2944
IMGUI_API bool IsPopupOpen(const char *str_id, ImGuiPopupFlags flags=0)
Definition imgui.cpp:9994
IMGUI_API bool IsItemVisible()
Definition imgui.cpp:5160
IMGUI_API void RemoveSettingsHandler(const char *type_name)
Definition imgui.cpp:12585
IMGUI_API void PopButtonRepeat()
Definition imgui.cpp:7037
IMGUI_API bool IsMouseDragging(ImGuiMouseButton button, float lock_threshold=-1.0f)
Definition imgui.cpp:8169
IMGUI_API void DebugNodeWindowsListByBeginStackParent(ImGuiWindow **windows, int windows_size, ImGuiWindow *parent_in_begin_stack)
Definition imgui.cpp:14209
IMGUI_API void SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect &rect_rel)
Definition imgui.cpp:10519
IMGUI_API ImGuiID GetItemID()
Definition imgui.cpp:5194
IMGUI_API void TextV(const char *fmt, va_list args) IM_FMTLIST(1)
ImRect WindowRectRelToAbs(ImGuiWindow *window, const ImRect &r)
IMGUI_API bool BeginPopup(const char *str_id, ImGuiWindowFlags flags=0)
Definition imgui.cpp:10231
IMGUI_API void ShowFontAtlas(ImFontAtlas *atlas)
Definition imgui.cpp:13275
IMGUI_API const char * GetClipboardText()
Definition imgui.cpp:4061
IMGUI_API bool IsItemClicked(ImGuiMouseButton mouse_button=0)
Definition imgui.cpp:5125
IMGUI_API void PushClipRect(const ImVec2 &clip_rect_min, const ImVec2 &clip_rect_max, bool intersect_with_current_clip_rect)
Definition imgui.cpp:4739
IMGUI_API void SetWindowFontScale(float scale)
Definition imgui.cpp:7429
IMGUI_API void SetNextItemWidth(float item_width)
Definition imgui.cpp:9404
IMGUI_API void DebugRenderKeyboardPreview(ImDrawList *draw_list)
Definition imgui.cpp:13177
IMGUI_API void PopStyleVar(int count=1)
Definition imgui.cpp:3081
IMGUI_API void SetNextWindowSizeConstraints(const ImVec2 &size_min, const ImVec2 &size_max, ImGuiSizeCallback custom_callback=NULL, void *custom_callback_data=NULL)
Definition imgui.cpp:7361
IMGUI_API const ImGuiPayload * GetDragDropPayload()
Definition imgui.cpp:12251
IMGUI_API void ClearActiveID()
Definition imgui.cpp:3799
IMGUI_API ImGuiWindowSettings * FindWindowSettingsByID(ImGuiID id)
Definition imgui.cpp:12751
IMGUI_API bool BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags)
Definition imgui.cpp:9900
IMGUI_API void Separator()
IMGUI_API void Initialize()
Definition imgui.cpp:3486
IMGUI_API void GetTypematicRepeatRate(ImGuiInputFlags flags, float *repeat_delay, float *repeat_rate)
Definition imgui.cpp:7797
IMGUI_API const char * GetKeyName(ImGuiKey key)
Definition imgui.cpp:7741
bool IsNamedKey(ImGuiKey key)
IMGUI_API ImGuiID AddContextHook(ImGuiContext *context, const ImGuiContextHook *hook)
Definition imgui.cpp:3603
IMGUI_API void BringWindowToDisplayFront(ImGuiWindow *window)
Definition imgui.cpp:6803
IMGUI_API bool TreeNodeEx(const char *label, ImGuiTreeNodeFlags flags=0)
IMGUI_API ImGuiID GetWindowResizeCornerID(ImGuiWindow *window, int n)
Definition imgui.cpp:5621
IMGUI_API bool IsMousePosValid(const ImVec2 *mouse_pos=NULL)
Definition imgui.cpp:8194
IMGUI_API ImVec2 GetMouseDragDelta(ImGuiMouseButton button=0, float lock_threshold=-1.0f)
Definition imgui.cpp:8217
IMGUI_API void EndFrame()
Definition imgui.cpp:4836
IMGUI_API void DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList *out_draw_list, const ImDrawList *draw_list, const ImDrawCmd *draw_cmd, bool show_mesh, bool show_aabb)
Definition imgui.cpp:13924
ImGuiKey MouseButtonToKey(ImGuiMouseButton button)
IMGUI_API void NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags)
Definition imgui.cpp:10902
IMGUI_API const char * GetStyleColorName(ImGuiCol idx)
Definition imgui.cpp:3102
IMGUI_API void MemFree(void *ptr)
Definition imgui.cpp:4053
IMGUI_API void StyleColorsDark(ImGuiStyle *dst=NULL)
IMGUI_API const char * SaveIniSettingsToMemory(size_t *out_ini_size=NULL)
Definition imgui.cpp:12711
IMGUI_API void PushID(const char *str_id)
Definition imgui.cpp:7524
IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow *window)
Definition imgui.cpp:3751
IMGUI_API void SetCurrentContext(ImGuiContext *ctx)
Definition imgui.cpp:3428
IMGUI_API void SameLine(float offset_from_start_x=0.0f, float spacing=-1.0f)
Definition imgui.cpp:9294
IMGUI_API void GetKeyChordName(ImGuiKeyChord key_chord, char *out_buf, int out_buf_size)
Definition imgui.cpp:7766
IMGUI_API ImDrawListSharedData * GetDrawListSharedData()
Definition imgui.cpp:4149
IMGUI_API bool IsWindowCollapsed()
Definition imgui.cpp:7306
IMGUI_API bool IsMouseDoubleClicked(ImGuiMouseButton button)
Definition imgui.cpp:8125
IMGUI_API bool TestShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id)
Definition imgui.cpp:8001
IMGUI_API bool IsMouseClicked(ImGuiMouseButton button, bool repeat=false)
Definition imgui.cpp:8084
IMGUI_API bool IsItemActive()
Definition imgui.cpp:5083
IMGUI_API const ImGuiDataVarInfo * GetStyleVarInfo(ImGuiStyleVar idx)
Definition imgui.cpp:3046
IMGUI_API void LogFinish()
Definition imgui.cpp:12452
IMGUI_API ImGuiWindowSettings * CreateNewWindowSettings(const char *name)
Definition imgui.cpp:12727
IMGUI_API bool BeginListBox(const char *label, const ImVec2 &size=ImVec2(0, 0))
IMGUI_API bool IsItemToggledOpen()
Definition imgui.cpp:5130
IMGUI_API ImVec2 GetCursorPos()
Definition imgui.cpp:9339
IMGUI_API ImVec2 GetFontTexUvWhitePixel()
Definition imgui.cpp:7424
IMGUI_API ImVec2 FindBestWindowPosForPopup(ImGuiWindow *window)
Definition imgui.cpp:10460
IMGUI_API void SetTooltip(const char *fmt,...) IM_FMTARGS(1)
Definition imgui.cpp:9950
IMGUI_API ImGuiIO & GetIO()
Definition imgui.cpp:4079
IMGUI_API void SetScrollHereX(float center_x_ratio=0.5f)
Definition imgui.cpp:9866
IMGUI_API void DebugTextEncoding(const char *text)
Definition imgui.cpp:13226
IMGUI_API void SetItemAllowOverlap()
Definition imgui.cpp:5174
IMGUI_API ImVec2 GetItemRectSize()
Definition imgui.cpp:5212
IMGUI_API ImGuiID GetID(const char *str_id)
Definition imgui.cpp:7594
IMGUI_API void BringWindowToDisplayBack(ImGuiWindow *window)
Definition imgui.cpp:6818
IMGUI_API void SetNextWindowScroll(const ImVec2 &scroll)
Definition imgui.cpp:7379
IMGUI_API void TextColored(const ImVec4 &col, const char *fmt,...) IM_FMTARGS(2)
IMGUI_API void SetItemDefaultFocus()
Definition imgui.cpp:7493
IMGUI_API bool Button(const char *label, const ImVec2 &size=ImVec2(0, 0))
IMGUI_API void OpenPopupOnItemClick(const char *str_id=NULL, ImGuiPopupFlags popup_flags=1)
Definition imgui.cpp:10299
IMGUI_API void SetTooltipV(const char *fmt, va_list args) IM_FMTLIST(1)
Definition imgui.cpp:9943
IMGUI_API ImGuiID GetKeyOwner(ImGuiKey key)
Definition imgui.cpp:8754
IMGUI_API ImGuiMouseCursor GetMouseCursor()
Definition imgui.cpp:8242
IMGUI_API void UpdateMouseMovingWindowNewFrame()
Definition imgui.cpp:4179
IMGUI_API float GetScrollY()
Definition imgui.cpp:9783
IMGUI_API ImVec2 GetItemRectMax()
Definition imgui.cpp:5206
IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiCond cond=0)
Definition imgui.cpp:7386
IMGUI_API double GetTime()
Definition imgui.cpp:4093
IMGUI_API bool NavMoveRequestButNoResultYet()
Definition imgui.cpp:10855
IMGUI_API ImVec2 GetContentRegionAvail()
Definition imgui.cpp:9537
IMGUI_API ImVec2 GetWindowPos()
Definition imgui.cpp:7193
IMGUI_API void SetScrollY(float scroll_y)
Definition imgui.cpp:9821
IMGUI_API void TreePop()
IMGUI_API void BeginGroup()
Definition imgui.cpp:9559
IMGUI_API void NavMoveRequestCancel()
Definition imgui.cpp:10894
IMGUI_API ImFont * GetFont()
Definition imgui.cpp:7414
IMGUI_API bool BeginPopupContextItem(const char *str_id=NULL, ImGuiPopupFlags popup_flags=1)
Definition imgui.cpp:10328
IMGUI_API ImGuiKeyRoutingData * GetShortcutRoutingData(ImGuiKeyChord key_chord)
Definition imgui.cpp:7874
IMGUI_API float GetWindowHeight()
Definition imgui.cpp:7187
IMGUI_API bool SetDragDropPayload(const char *type, const void *data, size_t sz, ImGuiCond cond=0)
Definition imgui.cpp:12100
IMGUI_API void RenderBullet(ImDrawList *draw_list, ImVec2 pos, ImU32 col)
IMGUI_API float GetWindowWidth()
Definition imgui.cpp:7181
IMGUI_API void DebugNodeTableSettings(ImGuiTableSettings *settings)
IMGUI_API bool IsKeyPressed(ImGuiKey key, bool repeat=true)
Definition imgui.cpp:8025
IMGUI_API int GetKeyPressedAmount(ImGuiKey key, float repeat_delay, float rate)
Definition imgui.cpp:7810
IMGUI_API bool ItemHoverable(const ImRect &bb, ImGuiID id)
Definition imgui.cpp:3942
IMGUI_API bool IsWindowWithinBeginStackOf(ImGuiWindow *window, ImGuiWindow *potential_parent)
Definition imgui.cpp:7085
IMGUI_API void TableSettingsAddSettingsHandler()
IMGUI_API void SetNextItemOpen(bool is_open, ImGuiCond cond=0)
IMGUI_API void TableSetupColumn(const char *label, ImGuiTableColumnFlags flags=0, float init_width_or_weight=0.0f, ImGuiID user_id=0)
IMGUI_API void PushItemWidth(float item_width)
Definition imgui.cpp:9412
IMGUI_API void LoadIniSettingsFromDisk(const char *ini_filename)
Definition imgui.cpp:12612
IMGUI_API void LogToBuffer(int auto_open_depth=-1)
Definition imgui.cpp:12444
IMGUI_API bool TreeNode(const char *label)
IMGUI_API void TableGcCompactSettings()
IMGUI_API bool CloseButton(ImGuiID id, const ImVec2 &pos)
IMGUI_API void SetCurrentFont(ImFont *font)
Definition imgui.cpp:6933
IMGUI_API void DebugNodeDrawList(ImGuiWindow *window, const ImDrawList *draw_list, const char *label)
Definition imgui.cpp:13830
IMGUI_API ImGuiContext * CreateContext(ImFontAtlas *shared_font_atlas=NULL)
Definition imgui.cpp:3452
IMGUI_API void NavInitRequestApplyResult()
Definition imgui.cpp:11228
IMGUI_API void SetCursorPos(const ImVec2 &local_pos)
Definition imgui.cpp:9357
IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags=0)
Definition imgui.cpp:7151
IMGUI_API void End()
Definition imgui.cpp:6741
IMGUI_API void DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void *data_id, const void *data_id_end)
Definition imgui.cpp:14421
IMGUI_API void RenderDragDropTargetRect(const ImRect &bb)
Definition imgui.cpp:12246
IMGUI_API void Scrollbar(ImGuiAxis axis)
IMGUI_API bool IsItemActivated()
Definition imgui.cpp:5091
IMGUI_API bool IsRectVisible(const ImVec2 &size)
Definition imgui.cpp:7612
IMGUI_API bool Checkbox(const char *label, bool *v)
IMGUI_API bool SliderInt(const char *label, int *v, int v_min, int v_max, const char *format="%d", ImGuiSliderFlags flags=0)
IMGUI_API bool Begin(const char *name, bool *p_open=NULL, ImGuiWindowFlags flags=0)
Definition imgui.cpp:6050
IMGUI_API void ShowStackToolWindow(bool *p_open=NULL)
Definition imgui.cpp:14486
IMGUI_API const char * TabBarGetTabName(ImGuiTabBar *tab_bar, ImGuiTabItem *tab)
IMGUI_API bool SmallButton(const char *label)
IMGUI_API void SetStateStorage(ImGuiStorage *storage)
Definition imgui.cpp:7512
IMGUI_API float GetTreeNodeToLabelSpacing()
IMGUI_API bool BeginChild(const char *str_id, const ImVec2 &size=ImVec2(0, 0), bool border=false, ImGuiWindowFlags flags=0)
Definition imgui.cpp:5269
IMGUI_API bool ItemAdd(const ImRect &bb, ImGuiID id, const ImRect *nav_bb=NULL, ImGuiItemFlags extra_flags=0)
Definition imgui.cpp:9215
IMGUI_API const ImGuiPayload * AcceptDragDropPayload(const char *type, ImGuiDragDropFlags flags=0)
Definition imgui.cpp:12207
IMGUI_API void SetActiveIdUsingAllKeyboardKeys()
Definition imgui.cpp:5185
IMGUI_API void DebugLocateItem(ImGuiID target_id)
Definition imgui.cpp:14316
IMGUI_API void CallContextHooks(ImGuiContext *context, ImGuiContextHookType type)
Definition imgui.cpp:3624
IMGUI_API void PushButtonRepeat(bool repeat)
Definition imgui.cpp:7032
IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border=true, float rounding=0.0f)
Definition imgui.cpp:3333
IMGUI_API void ClosePopupsExceptModals()
Definition imgui.cpp:10133
IMGUI_API void SetCursorScreenPos(const ImVec2 &pos)
Definition imgui.cpp:9329
IMGUI_API bool BeginChildEx(const char *name, ImGuiID id, const ImVec2 &size_arg, bool border, ImGuiWindowFlags flags)
Definition imgui.cpp:5218
IMGUI_API const char * GetVersion()
Definition imgui.cpp:4074
IMGUI_API bool IsItemEdited()
Definition imgui.cpp:5166
IMGUI_API void SetWindowSize(const ImVec2 &size, ImGuiCond cond=0)
Definition imgui.cpp:7266
IMGUI_API bool ButtonBehavior(const ImRect &bb, ImGuiID id, bool *out_hovered, bool *out_held, ImGuiButtonFlags flags=0)
IMGUI_API ImVec2 GetItemRectMin()
Definition imgui.cpp:5200
IMGUI_API void PopFocusScope()
Definition imgui.cpp:7452
IMGUI_API float CalcWrapWidthForPos(const ImVec2 &pos, float wrap_pos_x)
Definition imgui.cpp:4020
IMGUI_API void LogSetNextTextDecoration(const char *prefix, const char *suffix)
Definition imgui.cpp:12391
IMGUI_API void SetScrollFromPosY(float local_y, float center_y_ratio=0.5f)
Definition imgui.cpp:9859
IMGUI_API bool IsDragDropPayloadBeingAccepted()
Definition imgui.cpp:12201
IMGUI_API bool BeginPopupContextVoid(const char *str_id=NULL, ImGuiPopupFlags popup_flags=1)
Definition imgui.cpp:10356
IMGUI_API void LocalizeRegisterEntries(const ImGuiLocEntry *entries, int count)
Definition imgui.cpp:12872
IMGUI_API void DebugNodeColumns(ImGuiOldColumns *columns)
Definition imgui.cpp:13819
IMGUI_API void EndListBox()
IMGUI_API ImGuiWindow * GetTopMostPopupModal()
Definition imgui.cpp:10003
IMGUI_API void TableEndRow(ImGuiTable *table)
IMGUI_API void Indent(float indent_w=0.0f)
Definition imgui.cpp:9387
IMGUI_API bool BeginPopupModal(const char *name, bool *p_open=NULL, ImGuiWindowFlags flags=0)
Definition imgui.cpp:10246
IMGUI_API bool IsWindowNavFocusable(ImGuiWindow *window)
Definition imgui.cpp:7176
IMGUI_API void PushMultiItemsWidths(int components, float width_full)
Definition imgui.cpp:9421
IMGUI_API void UpdateMouseMovingWindowEndFrame()
Definition imgui.cpp:4215
IMGUI_API bool IsWindowChildOf(ImGuiWindow *window, ImGuiWindow *potential_parent, bool popup_hierarchy)
Definition imgui.cpp:7069
IMGUI_API float GetScrollX()
Definition imgui.cpp:9777
IMGUI_API void RenderTextClippedEx(ImDrawList *draw_list, const ImVec2 &pos_min, const ImVec2 &pos_max, const char *text, const char *text_end, const ImVec2 *text_size_if_known, const ImVec2 &align=ImVec2(0, 0), const ImRect *clip_rect=NULL)
Definition imgui.cpp:3230
IMGUI_API void LogToClipboard(int auto_open_depth=-1)
Definition imgui.cpp:12436
IMGUI_API ImDrawList * GetForegroundDrawList()
Definition imgui.cpp:4143
IMGUI_API ImRect GetPopupAllowedExtentRect(ImGuiWindow *window)
Definition imgui.cpp:10450
IMGUI_API void PushTextWrapPos(float wrap_local_pos_x=0.0f)
Definition imgui.cpp:7042
IMGUI_API ImVec4 ColorConvertU32ToFloat4(ImU32 in)
Definition imgui.cpp:2197
IMGUI_API const char * FindRenderedTextEnd(const char *text, const char *text_end=NULL)
Definition imgui.cpp:3173
IMGUI_API void DebugLocateItemOnHover(ImGuiID target_id)
Definition imgui.cpp:14323
IMGUI_API void ResetMouseDragDelta(ImGuiMouseButton button=0)
Definition imgui.cpp:8230
IMGUI_API void PushStyleColor(ImGuiCol idx, ImU32 col)
Definition imgui.cpp:2977
IMGUI_API ImVec2 GetWindowContentRegionMin()
Definition imgui.cpp:9544
IMGUI_API bool Shortcut(ImGuiKeyChord key_chord, ImGuiID owner_id=0, ImGuiInputFlags flags=0)
Definition imgui.cpp:8842
IMGUI_API void LogRenderedText(const ImVec2 *ref_pos, const char *text, const char *text_end=NULL)
Definition imgui.cpp:12315
bool IsNamedKeyOrModKey(ImGuiKey key)
IMGUI_API void LogButtons()
Definition imgui.cpp:12488
IMGUI_API ImVec2 GetKeyMagnitude2d(ImGuiKey key_left, ImGuiKey key_right, ImGuiKey key_up, ImGuiKey key_down)
Definition imgui.cpp:7821
IMGUI_API ImGuiViewport * GetMainViewport()
Definition imgui.cpp:12889
IMGUI_API bool IsClippedEx(const ImRect &bb, ImGuiID id)
Definition imgui.cpp:3998
IMGUI_API void SetAllocatorFunctions(ImGuiMemAllocFunc alloc_func, ImGuiMemFreeFunc free_func, void *user_data=NULL)
Definition imgui.cpp:3437
IMGUI_API void SetNextWindowBgAlpha(float alpha)
Definition imgui.cpp:7401
IMGUI_API void UpdateHoveredWindowAndCaptureFlags()
Definition imgui.cpp:4273
IMGUI_API float GetColumnOffsetFromNorm(const ImGuiOldColumns *columns, float offset_norm)
IMGUI_API bool IsKeyDown(ImGuiKey key)
Definition imgui.cpp:8010
IMGUI_API ImGuiWindow * FindWindowByID(ImGuiID id)
Definition imgui.cpp:5354
IMGUI_API void MarkItemEdited(ImGuiID id)
Definition imgui.cpp:3830
ImFont * GetDefaultFont()
IMGUI_API void GcCompactTransientWindowBuffers(ImGuiWindow *window)
Definition imgui.cpp:3729
IMGUI_API void SetWindowHitTestHole(ImGuiWindow *window, const ImVec2 &pos, const ImVec2 &size)
Definition imgui.cpp:7288
IMGUI_API void ClearIniSettings()
Definition imgui.cpp:12603
IMGUI_API ImVec2 CalcTextSize(const char *text, const char *text_end=NULL, bool hide_text_after_double_hash=false, float wrap_width=-1.0f)
Definition imgui.cpp:5001
IMGUI_API void GetAllocatorFunctions(ImGuiMemAllocFunc *p_alloc_func, ImGuiMemFreeFunc *p_free_func, void **p_user_data)
Definition imgui.cpp:3445
IMGUI_API void KeepAliveID(ImGuiID id)
Definition imgui.cpp:3821
IMGUI_API void UpdateWindowParentAndRootLinks(ImGuiWindow *window, ImGuiWindowFlags flags, ImGuiWindow *parent_window)
Definition imgui.cpp:5994
IMGUI_API void EndTabBar()
IMGUI_API float GetCursorPosY()
Definition imgui.cpp:9351
bool IsLegacyKey(ImGuiKey key)
IMGUI_API bool IsItemToggledSelection()
Definition imgui.cpp:5136
IMGUI_API void SetItemKeyOwner(ImGuiKey key, ImGuiInputFlags flags=0)
Definition imgui.cpp:8827
IMGUI_API void NavMoveRequestApplyResult()
Definition imgui.cpp:11386
IMGUI_API bool IsAnyItemFocused()
Definition imgui.cpp:5154
IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags)
Definition imgui.cpp:10208
IMGUI_API void SetFocusID(ImGuiID id, ImGuiWindow *window)
Definition imgui.cpp:10531
IMGUI_API void Dummy(const ImVec2 &size)
IMGUI_API bool IsItemDeactivatedAfterEdit()
Definition imgui.cpp:5108
IMGUI_API void DebugNodeWindowsList(ImVector< ImGuiWindow * > *windows, const char *label)
Definition imgui.cpp:14195
IMGUI_API void BringWindowToDisplayBehind(ImGuiWindow *window, ImGuiWindow *above_window)
Definition imgui.cpp:6832
IMGUI_API void LogBegin(ImGuiLogType type, int auto_open_depth)
Definition imgui.cpp:12374
IMGUI_API float GetFrameHeightWithSpacing()
Definition imgui.cpp:9507
IMGUI_API void DebugNodeStorage(ImGuiStorage *storage, const char *label)
Definition imgui.cpp:14055
IMGUI_API void LoadIniSettingsFromMemory(const char *ini_data, size_t ini_size=0)
Definition imgui.cpp:12624
IMGUI_API ImVec2 GetCursorStartPos()
Definition imgui.cpp:9381
IMGUI_API void LogToFile(int auto_open_depth=-1, const char *filename=NULL)
Definition imgui.cpp:12411
bool IsActiveIdUsingNavDir(ImGuiDir dir)
IMGUI_API bool BeginDragDropTargetCustom(const ImRect &bb, ImGuiID id)
Definition imgui.cpp:12144
IMGUI_API void ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, void *user_data=NULL)
Definition imgui.cpp:9042
IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow *window, ImGuiNavMoveFlags move_flags)
Definition imgui.cpp:10916
IMGUI_API void TextUnformatted(const char *text, const char *text_end=NULL)
IMGUI_API ImVec2 GetWindowContentRegionMax()
Definition imgui.cpp:9550
IMGUI_API void PopStyleColor(int count=1)
Definition imgui.cpp:2997
IMGUI_API void ScrollToRect(ImGuiWindow *window, const ImRect &rect, ImGuiScrollFlags flags=0)
Definition imgui.cpp:9699
IMGUI_API void LogTextV(const char *fmt, va_list args) IM_FMTLIST(1)
Definition imgui.cpp:12303
IMGUI_API void RenderText(ImVec2 pos, const char *text, const char *text_end=NULL, bool hide_text_after_hash=true)
Definition imgui.cpp:3186
IMGUI_API bool IsWindowAppearing()
Definition imgui.cpp:7312
IMGUI_API void EndTable()
IMGUI_API void OpenPopup(const char *str_id, ImGuiPopupFlags popup_flags=0)
Definition imgui.cpp:10023
IMGUI_API void EndDisabled()
Definition imgui.cpp:7009
IMGUI_API void Text(const char *fmt,...) IM_FMTARGS(1)
IMGUI_API bool DebugCheckVersionAndDataLayout(const char *version_str, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_drawvert, size_t sz_drawidx)
Definition imgui.cpp:8883
IMGUI_API ImDrawList * GetWindowDrawList()
Definition imgui.cpp:7408
IMGUI_API float GetTextLineHeightWithSpacing()
Definition imgui.cpp:9495
IMGUI_API bool Combo(const char *label, int *current_item, const char *const items[], int items_count, int popup_max_height_in_items=-1)
IMGUI_API ImGuiStorage * GetStateStorage()
Definition imgui.cpp:7518
IMGUI_API ImVec2 CalcWindowNextAutoFitSize(ImGuiWindow *window)
Definition imgui.cpp:5544
IMGUI_API ImGuiWindowSettings * FindWindowSettingsByWindow(ImGuiWindow *window)
Definition imgui.cpp:12761
IMGUI_API void SetNavWindow(ImGuiWindow *window)
Definition imgui.cpp:10507
IMGUI_API void SetClipboardText(const char *text)
Definition imgui.cpp:4067
IMGUI_API void RenderTextWrapped(ImVec2 pos, const char *text, const char *text_end, float wrap_width)
Definition imgui.cpp:3212
IMGUI_API void LogText(const char *fmt,...) IM_FMTARGS(1)
Definition imgui.cpp:12291
IMGUI_API void DebugNodeViewport(ImGuiViewportP *viewport)
Definition imgui.cpp:14110
IMGUI_API void EndPopup()
Definition imgui.cpp:10278
IMGUI_API bool InputText(const char *label, char *buf, size_t buf_size, ImGuiInputTextFlags flags=0, ImGuiInputTextCallback callback=NULL, void *user_data=NULL)
IMGUI_API ImGuiWindow * GetTopMostAndVisiblePopupModal()
Definition imgui.cpp:10013
IMGUI_API void PopItemFlag()
Definition imgui.cpp:6980
IMGUI_API void TextDisabled(const char *fmt,...) IM_FMTARGS(1)
IMGUI_API ImVec2 GetWindowSize()
Definition imgui.cpp:7235
IMGUI_API void DebugLog(const char *fmt,...) IM_FMTARGS(1)
Definition imgui.cpp:14230
IMGUI_API void SetWindowPos(const ImVec2 &pos, ImGuiCond cond=0)
Definition imgui.cpp:7223
IMGUI_API void NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags)
Definition imgui.cpp:10862
IMGUI_API void GcCompactTransientMiscBuffers()
Definition imgui.cpp:3717
IMGUI_API bool DragFloat(const char *label, float *v, float v_speed=1.0f, float v_min=0.0f, float v_max=0.0f, const char *format="%.3f", ImGuiSliderFlags flags=0)
IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val)
Definition imgui.cpp:3053
IMGUI_API float GetTextLineHeight()
Definition imgui.cpp:9489
IMGUI_API void RemoveContextHook(ImGuiContext *context, ImGuiID hook_to_remove)
Definition imgui.cpp:3613
IMGUI_API void SetNextWindowContentSize(const ImVec2 &size)
Definition imgui.cpp:7372
IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags=0)
Definition imgui.cpp:7118
IMGUI_API void ColorConvertRGBtoHSV(float r, float g, float b, float &out_h, float &out_s, float &out_v)
Definition imgui.cpp:2219
IMGUI_API void ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, void *user_data=NULL)
Definition imgui.cpp:9015
ImGuiTableInstanceData * TableGetInstanceData(ImGuiTable *table, int instance_no)
IMGUI_API void UpdateInputEvents(bool trickle_fast_inputs)
Definition imgui.cpp:8638
IMGUI_API void SetNextWindowSize(const ImVec2 &size, ImGuiCond cond=0)
Definition imgui.cpp:7352
IMGUI_API float GetScrollMaxY()
Definition imgui.cpp:9795
IMGUI_API ImDrawList * GetBackgroundDrawList()
Definition imgui.cpp:4132
IMGUI_API void RenderTextClipped(const ImVec2 &pos_min, const ImVec2 &pos_max, const char *text, const char *text_end, const ImVec2 *text_size_if_known, const ImVec2 &align=ImVec2(0, 0), const ImRect *clip_rect=NULL)
Definition imgui.cpp:3258
IMGUI_API float CalcItemWidth()
Definition imgui.cpp:9445
IMGUI_API ImGuiID GetIDWithSeed(const char *str_id_begin, const char *str_id_end, ImGuiID seed)
Definition imgui.cpp:7569
IMGUI_API void NewFrame()
Definition imgui.cpp:4349
IMGUI_API bool CheckboxFlags(const char *label, int *flags, int flags_value)
IMGUI_API ImVec2 FindBestWindowPosForPopupEx(const ImVec2 &ref_pos, const ImVec2 &size, ImGuiDir *last_dir, const ImRect &r_outer, const ImRect &r_avoid, ImGuiPopupPositionPolicy policy)
Definition imgui.cpp:10375
IMGUI_API void Render()
Definition imgui.cpp:4934
IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond=0)
Definition imgui.cpp:7301
IMGUI_API ImDrawData * GetDrawData()
Definition imgui.cpp:4086
IMGUI_API void ScrollToItem(ImGuiScrollFlags flags=0)
Definition imgui.cpp:9692
IMGUI_API void DebugNodeInputTextState(ImGuiInputTextState *state)
IMGUI_API void DestroyContext(ImGuiContext *ctx=NULL)
Definition imgui.cpp:3463
IMGUI_API int CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate)
Definition imgui.cpp:7783
IMGUI_API void PopID()
Definition imgui.cpp:7587
IMGUI_API void SetHoveredID(ImGuiID id)
Definition imgui.cpp:3804
IMGUI_API void PushTabStop(bool tab_stop)
Definition imgui.cpp:7022
IMGUI_API ImGuiStyle & GetStyle()
Definition imgui.cpp:2938
void DebugStartItemPicker()
IMGUI_API void FocusTopMostWindowUnderOne(ImGuiWindow *under_this_window, ImGuiWindow *ignore_window)
Definition imgui.cpp:6901
IMGUI_API ImGuiWindow * FindWindowByName(const char *name)
Definition imgui.cpp:5360
IMGUI_API ImU32 ColorConvertFloat4ToU32(const ImVec4 &in)
Definition imgui.cpp:2207
IMGUI_API ImVec2 GetMousePos()
Definition imgui.cpp:8178
IMGUI_API void OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags=ImGuiPopupFlags_None)
Definition imgui.cpp:10040
IMGUI_API void SetNextFrameWantCaptureKeyboard(bool want_capture_keyboard)
Definition imgui.cpp:8603
IMGUI_API ImVec2 GetMousePosOnOpeningCurrentPopup()
Definition imgui.cpp:8185
IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags=0)
Definition imgui.cpp:11973
IMGUI_API bool SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id=0, ImGuiInputFlags flags=0)
Definition imgui.cpp:7966
IMGUI_API void SetNextWindowFocus()
Definition imgui.cpp:7395
IMGUI_API void SetKeyOwner(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags=0)
Definition imgui.cpp:8807
IMGUI_API bool BeginDragDropTarget()
Definition imgui.cpp:12171
ImGuiWindow * GetCurrentWindow()
IMGUI_API void EndChildFrame()
Definition imgui.cpp:5342
IMGUI_API void ActivateItem(ImGuiID id)
Definition imgui.cpp:7438
IMGUI_API float GetFontSize()
Definition imgui.cpp:7419
IMGUI_API void PushFont(ImFont *font)
Definition imgui.cpp:6949
IMGUI_API bool IsWindowAbove(ImGuiWindow *potential_above, ImGuiWindow *potential_below)
Definition imgui.cpp:7098
IMGUI_API void ClearWindowSettings(const char *name)
Definition imgui.cpp:12770
IMGUI_API void DebugNodeTabBar(ImGuiTabBar *tab_bar, const char *label)
Definition imgui.cpp:14068
IMGUI_API void SetWindowFocus()
Definition imgui.cpp:7324
IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled)
Definition imgui.cpp:6967
IMGUI_API void SetScrollHereY(float center_y_ratio=0.5f)
Definition imgui.cpp:9879
IMGUI_API void EndTooltip()
Definition imgui.cpp:9937
bool IsAliasKey(ImGuiKey key)
IMGUI_API bool TableNextColumn()
IMGUI_API bool IsItemHovered(ImGuiHoveredFlags flags=0)
Definition imgui.cpp:3871
IMGUI_API void SetMouseCursor(ImGuiMouseCursor cursor_type)
Definition imgui.cpp:8248
IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_w, float default_h)
Definition imgui.cpp:9467
IMGUI_API ImGuiWindow * FindBottomMostVisibleWindowWithinBeginStack(ImGuiWindow *window)
Definition imgui.cpp:4780
bool IsGamepadKey(ImGuiKey key)
IMGUI_API int FindWindowDisplayIndex(ImGuiWindow *window)
Definition imgui.cpp:6854
IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2 &pos)
IMGUI_API bool IsAnyItemActive()
Definition imgui.cpp:5148
IMGUI_API void PushOverrideID(ImGuiID id)
Definition imgui.cpp:7557
IMGUI_API void PushFocusScope(ImGuiID id)
Definition imgui.cpp:7445
IMGUI_API bool TestKeyOwner(ImGuiKey key, ImGuiID owner_id)
Definition imgui.cpp:8774
IMGUI_API float GetNavTweakPressedAmount(ImGuiAxis axis)
Definition imgui.cpp:11043
IMGUI_API bool IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold=-1.0f)
Definition imgui.cpp:8160
IMGUI_API void LogToTTY(int auto_open_depth=-1)
Definition imgui.cpp:12398
IMGUI_API void SetScrollFromPosX(float local_x, float center_x_ratio=0.5f)
Definition imgui.cpp:9853
IMGUI_API void PopItemWidth()
Definition imgui.cpp:9436
IMGUI_API void SetWindowHiddendAndSkipItemsForCurrentFrame(ImGuiWindow *window)
Definition imgui.cpp:7295
ImGuiKey ConvertSingleModFlagToKey(ImGuiKey key)
IMGUI_API void Unindent(float indent_w=0.0f)
Definition imgui.cpp:9395
IMGUI_API ImGuiID GetHoveredID()
Definition imgui.cpp:3813
IMGUI_API void DebugNodeFontGlyph(ImFont *font, const ImFontGlyph *glyph)
Definition imgui.cpp:14044
IMGUI_API void ErrorCheckUsingSetCursorPosToExtendParentBoundaries()
Definition imgui.cpp:8911
ImGuiKeyOwnerData * GetKeyOwnerData(ImGuiKey key)
IMGUI_API void GcAwakeTransientWindowBuffers(ImGuiWindow *window)
Definition imgui.cpp:3741
IMGUI_API void NavMoveRequestResolveWithLastItem(ImGuiNavItemData *result)
Definition imgui.cpp:10886
IMGUI_API const ImVec4 & GetStyleColorVec4(ImGuiCol idx)
Definition imgui.cpp:2960
IMGUI_API void DebugNodeWindowSettings(ImGuiWindowSettings *settings)
Definition imgui.cpp:14185
IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2 &size, const ImVec2 &uv0=ImVec2(0, 0), const ImVec2 &uv1=ImVec2(1, 1), const ImVec4 &tint_col=ImVec4(1, 1, 1, 1), const ImVec4 &border_col=ImVec4(0, 0, 0, 0))
IMGUI_API ImGuiSettingsHandler * FindSettingsHandler(const char *type_name)
Definition imgui.cpp:12592
IMGUI_API bool IsItemDeactivated()
Definition imgui.cpp:5100
IMGUI_API void SetWindowViewport(ImGuiWindow *window, ImGuiViewportP *viewport)
Definition imgui.cpp:12895
IMGUI_API void ClearDragDrop()
Definition imgui.cpp:11952
IMGUI_API bool IsDragDropActive()
Definition imgui.cpp:11946
IMGUI_API ImVec2 GetCursorScreenPos()
Definition imgui.cpp:9320
IMGUI_API ImVec2 GetContentRegionMaxAbs()
Definition imgui.cpp:9527
IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding=0.0f)
Definition imgui.cpp:3346
IMGUI_API bool IsItemFocused()
Definition imgui.cpp:5115
IMGUI_API void RenderMouseCursor(ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow)
Definition imgui.cpp:3390
IMGUI_API void AddSettingsHandler(const ImGuiSettingsHandler *handler)
Definition imgui.cpp:12578
IMGUI_API void FocusWindow(ImGuiWindow *window)
Definition imgui.cpp:6861
IMGUI_API void DebugNodeFont(ImFont *font)
Definition imgui.cpp:13954
IMGUI_API bool IsMouseHoveringRect(const ImVec2 &r_min, const ImVec2 &r_max, bool clip=true)
Definition imgui.cpp:8142
ImGuiKeyChord ConvertShortcutMod(ImGuiKeyChord key_chord)
IMGUI_API void AlignTextToFramePadding()
IMGUI_API void NavInitWindow(ImGuiWindow *window, bool force_reinit)
Definition imgui.cpp:10983
IMGUI_API void CalcListClipping(int items_count, float items_height, int *out_items_display_start, int *out_items_display_end)
Definition imgui.cpp:2616
IMGUI_API bool IsMouseReleased(ImGuiMouseButton button)
Definition imgui.cpp:8111
IMGUI_API float GetFrameHeight()
Definition imgui.cpp:9501
IMGUI_API void SetCursorPosX(float local_x)
Definition imgui.cpp:9365
IMGUI_API void EndDragDropTarget()
Definition imgui.cpp:12257
IMGUI_API void SetKeyboardFocusHere(int offset=0)
Definition imgui.cpp:7461
IMGUI_API void DebugLocateItemResolveWithLastItem()
Definition imgui.cpp:14332
IMGUI_API void TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n=-1)
IMGUI_API void BeginDisabled(bool disabled=true)
Definition imgui.cpp:6994
IMGUI_API void DebugNodeTable(ImGuiTable *table)
IMGUI_API void CloseCurrentPopup()
Definition imgui.cpp:10177
IMGUI_API void Shutdown()
Definition imgui.cpp:3526
IMGUI_API ImGuiID GetWindowResizeBorderID(ImGuiWindow *window, ImGuiDir dir)
Definition imgui.cpp:5631
IMGUI_API bool IsMouseDown(ImGuiMouseButton button)
Definition imgui.cpp:8070
IMGUI_API void * MemAlloc(size_t size)
Definition imgui.cpp:4045
IMGUI_API void MarkIniSettingsDirty()
Definition imgui.cpp:12563
IMGUI_API void ItemSize(const ImVec2 &size, float text_baseline_y=-1.0f)
Definition imgui.cpp:9176
IMGUI_API void PopClipRect()
Definition imgui.cpp:4746
IMGUI_API ImGuiKeyData * GetKeyData(ImGuiKey key)
Definition imgui.cpp:7688
IMGUI_API bool BeginPopupContextWindow(const char *str_id=NULL, ImGuiPopupFlags popup_flags=1)
Definition imgui.cpp:10342
IMGUI_API void ShowDebugLogWindow(bool *p_open=NULL)
Definition imgui.cpp:14249
IMGUI_API bool IsKeyReleased(ImGuiKey key)
Definition imgui.cpp:8055
IMGUI_API void TableGcCompactTransientBuffers(ImGuiTable *table)
IMGUI_API float GetScrollMaxX()
Definition imgui.cpp:9789
IMGUI_API ImGuiContext * GetCurrentContext()
Definition imgui.cpp:3423
IMGUI_API void PopFont()
Definition imgui.cpp:6959
IMGUI_API void DebugRenderViewportThumbnail(ImDrawList *draw_list, ImGuiViewportP *viewport, const ImRect &bb)
Definition imgui.cpp:13125
IMGUI_API void PopTabStop()
Definition imgui.cpp:7027
IMGUI_API void BulletText(const char *fmt,...) IM_FMTARGS(1)
IMGUI_API void EndChild()
Definition imgui.cpp:5281
IMGUI_API void EndColumns()
IMGUI_API bool Selectable(const char *label, bool selected=false, ImGuiSelectableFlags flags=0, const ImVec2 &size=ImVec2(0, 0))
IMGUI_API void DebugLogV(const char *fmt, va_list args) IM_FMTLIST(1)
Definition imgui.cpp:14238
IMGUI_API void SaveIniSettingsToDisk(const char *ini_filename)
Definition imgui.cpp:12694
IMGUI_API void SetNextWindowPos(const ImVec2 &pos, ImGuiCond cond=0, const ImVec2 &pivot=ImVec2(0, 0))
Definition imgui.cpp:7342
IMGUI_API void RenderNavHighlight(const ImRect &bb, ImGuiID id, ImGuiNavHighlightFlags flags=ImGuiNavHighlightFlags_TypeDefault)
Definition imgui.cpp:3358
IMGUI_API void DebugNodeWindow(ImGuiWindow *window, const char *label)
Definition imgui.cpp:14130
IMGUI_API void StartMouseMovingWindow(ImGuiWindow *window)
Definition imgui.cpp:4154
IMGUI_API void TabBarQueueReorder(ImGuiTabBar *tab_bar, ImGuiTabItem *tab, int offset)
IMGUI_API void ShowMetricsWindow(bool *p_open=NULL)
Definition imgui.cpp:13296
IMGUI_API void SetNextFrameWantCaptureMouse(bool want_capture_mouse)
Definition imgui.cpp:8609
IMGUI_API void BringWindowToFocusFront(ImGuiWindow *window)
Definition imgui.cpp:6782
IMGUI_API int GetMouseClickedCount(ImGuiMouseButton button)
Definition imgui.cpp:8132
bool TestBit(int n) const
void SetBit(int n)
int size() const
T * alloc_chunk(size_t sz)
T * ptr_from_offset(int off)
T * next_chunk(T *p)
int offset_from_ptr(const T *p)
bool empty() const
unsigned int VtxOffset
Definition imgui.h:2436
ImVec4 ClipRect
Definition imgui.h:2434
unsigned int ElemCount
Definition imgui.h:2438
ImDrawCallback UserCallback
Definition imgui.h:2439
unsigned int IdxOffset
Definition imgui.h:2437
ImVector< ImDrawList * > Layers[2]
IMGUI_API void FlattenIntoSingleLayer()
Definition imgui.cpp:4695
int TotalIdxCount
Definition imgui.h:2669
ImVec2 DisplayPos
Definition imgui.h:2672
ImVec2 DisplaySize
Definition imgui.h:2673
ImDrawList ** CmdLists
Definition imgui.h:2671
void Clear()
Definition imgui.h:2678
bool Valid
Definition imgui.h:2667
ImVec2 FramebufferScale
Definition imgui.h:2674
int CmdListsCount
Definition imgui.h:2668
int TotalVtxCount
Definition imgui.h:2670
unsigned int _VtxCurrentIdx
Definition imgui.h:2546
IMGUI_API void _PopUnusedDrawCmd()
IMGUI_API void PopClipRect()
IMGUI_API void _ResetForNewFrame()
IMGUI_API void PushClipRect(const ImVec2 &clip_rect_min, const ImVec2 &clip_rect_max, bool intersect_with_current_clip_rect=false)
void PathStroke(ImU32 col, ImDrawFlags flags=0, float thickness=1.0f)
Definition imgui.h:2610
IMGUI_API void _ClearFreeMemory()
const char * _OwnerName
Definition imgui.h:2548
ImVector< ImDrawCmd > CmdBuffer
Definition imgui.h:2540
ImDrawVert * _VtxWritePtr
Definition imgui.h:2549
IMGUI_API void AddRectFilled(const ImVec2 &p_min, const ImVec2 &p_max, ImU32 col, float rounding=0.0f, ImDrawFlags flags=0)
IMGUI_API void PathArcToFast(const ImVec2 &center, float radius, int a_min_of_12, int a_max_of_12)
ImDrawIdx * _IdxWritePtr
Definition imgui.h:2550
IMGUI_API void PushTextureID(ImTextureID texture_id)
void PathLineTo(const ImVec2 &pos)
Definition imgui.h:2607
IMGUI_API void AddDrawCmd()
IMGUI_API void AddLine(const ImVec2 &p1, const ImVec2 &p2, ImU32 col, float thickness=1.0f)
ImVector< ImDrawVert > VtxBuffer
Definition imgui.h:2542
IMGUI_API void AddPolyline(const ImVec2 *points, int num_points, ImU32 col, ImDrawFlags flags, float thickness)
IMGUI_API void AddImage(ImTextureID user_texture_id, const ImVec2 &p_min, const ImVec2 &p_max, const ImVec2 &uv_min=ImVec2(0, 0), const ImVec2 &uv_max=ImVec2(1, 1), ImU32 col=IM_COL32_WHITE)
IMGUI_API void AddText(const ImVec2 &pos, ImU32 col, const char *text_begin, const char *text_end=NULL)
ImDrawListSharedData * _Data
Definition imgui.h:2547
IMGUI_API void AddRect(const ImVec2 &p_min, const ImVec2 &p_max, ImU32 col, float rounding=0.0f, ImDrawFlags flags=0, float thickness=1.0f)
ImDrawListFlags Flags
Definition imgui.h:2543
IMGUI_API void PopTextureID()
ImVector< ImDrawIdx > IdxBuffer
Definition imgui.h:2541
ImVector< ImVec4 > _ClipRectStack
Definition imgui.h:2551
void PathFillConvex(ImU32 col)
Definition imgui.h:2609
IMGUI_API void AddCircleFilled(const ImVec2 &center, float radius, ImU32 col, int num_segments=0)
IMGUI_API void PathArcTo(const ImVec2 &center, float radius, float a_min, float a_max, int num_segments=0)
const ImVec4 * TexUvLines
ImVector< ImVec2 > TempBuffer
ImDrawListFlags InitialFlags
void SetCircleTessellationMaxError(float max_error)
ImU32 col
Definition imgui.h:2454
ImVec2 uv
Definition imgui.h:2453
ImVec2 pos
Definition imgui.h:2452
ImVector< ImFont * > Fonts
Definition imgui.h:2864
bool IsBuilt() const
Definition imgui.h:2804
ImTextureID TexID
Definition imgui.h:2848
bool Locked
Definition imgui.h:2851
int TexWidth
Definition imgui.h:2860
int TexHeight
Definition imgui.h:2861
IMGUI_API bool GetMouseCursorTexData(ImGuiMouseCursor cursor, ImVec2 *out_offset, ImVec2 *out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2])
ImVec4 TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX+1]
Definition imgui.h:2867
ImFontAtlasFlags Flags
Definition imgui.h:2847
ImVec2 TexUvWhitePixel
Definition imgui.h:2863
char Name[40]
Definition imgui.h:2708
float AdvanceX
Definition imgui.h:2721
float X1
Definition imgui.h:2722
float X0
Definition imgui.h:2722
unsigned int Codepoint
Definition imgui.h:2720
float V0
Definition imgui.h:2723
float U0
Definition imgui.h:2723
float V1
Definition imgui.h:2723
unsigned int Visible
Definition imgui.h:2719
float Y1
Definition imgui.h:2722
float U1
Definition imgui.h:2723
float Y0
Definition imgui.h:2722
ImVector< ImFontGlyph > Glyphs
Definition imgui.h:2893
float EllipsisWidth
Definition imgui.h:2903
float FontSize
Definition imgui.h:2889
IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last)
short ConfigDataCount
Definition imgui.h:2899
ImWchar EllipsisChar
Definition imgui.h:2901
float Ascent
Definition imgui.h:2907
IMGUI_API void RenderChar(ImDrawList *draw_list, float size, const ImVec2 &pos, ImU32 col, ImWchar c) const
int MetricsTotalSurface
Definition imgui.h:2908
ImFontAtlas * ContainerAtlas
Definition imgui.h:2897
bool IsLoaded() const
Definition imgui.h:2917
float EllipsisCharStep
Definition imgui.h:2904
IMGUI_API const ImFontGlyph * FindGlyphNoFallback(ImWchar c) const
short EllipsisCharCount
Definition imgui.h:2902
float Descent
Definition imgui.h:2907
IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char *text_begin, const char *text_end=NULL, const char **remaining=NULL) const
ImWchar FallbackChar
Definition imgui.h:2900
float Scale
Definition imgui.h:2906
const ImFontConfig * ConfigData
Definition imgui.h:2898
ImGuiContextHookType Type
ImGuiContextHookCallback Callback
ImGuiID DebugLocateId
int WantCaptureKeyboardNextFrame
bool FontAtlasOwnedByContext
ImGuiID DebugHookIdInfo
ImGuiID NavActivateDownId
ImGuiPlatformImeData PlatformImeData
ImGuiID HoveredIdPreviousFrame
float FramerateSecPerFrame[60]
ImGuiKeyChord ConfigNavWindowingKeyPrev
ImVector< ImGuiPopupData > OpenPopupStack
ImVector< ImGuiWindow * > Windows
ImGuiNextWindowData NextWindowData
ImChunkStream< ImGuiWindowSettings > SettingsWindows
ImGuiNavLayer NavLayer
ImGuiID NavInitResultId
ImGuiID NavJustMovedToId
ImVector< ImGuiWindow * > WindowsFocusOrder
ImGuiDir NavMoveDir
ImVector< ImGuiWindow * > WindowsTempSortBuffer
ImVec2 WindowsHoverPadding
ImGuiID NavActivatePressedId
ImGuiWindow * MovingWindow
ImGuiKeyChord ConfigNavWindowingKeyNext
ImVec2 ActiveIdClickOffset
ImU8 DebugItemPickerMouseButton
ImGuiItemFlags CurrentItemFlags
bool ActiveIdUsingAllKeyboardKeys
ImGuiTextBuffer DebugLogBuf
const char * LocalizationTable[ImGuiLocKey_COUNT]
ImVector< ImGuiID > MenusIdSubmittedThisFrame
ImGuiStyle Style
ImGuiInputSource NavInputSource
ImGuiWindow * WheelingWindow
ImGuiInputSource ActiveIdSource
ImGuiMetricsConfig DebugMetricsConfig
bool NavWindowingToggleLayer
ImGuiPayload DragDropPayload
float WheelingWindowReleaseTimer
ImGuiNextItemData NextItemData
float DisabledAlphaBackup
ImGuiDebugLogFlags DebugLogFlags
ImGuiDir NavMoveClipDir
ImGuiLastItemData LastItemData
bool ActiveIdPreviousFrameHasBeenEditedBefore
const char * LogNextPrefix
ImGuiActivateFlags NavNextActivateFlags
float DragDropAcceptIdCurrRectSurface
ImGuiStackTool DebugStackTool
ImRect NavInitResultRectRel
ImVector< ImGuiPopupData > BeginPopupStack
ImVector< ImGuiPtrOrIndex > CurrentTabBarStack
ImGuiScrollFlags NavMoveScrollFlags
ImVector< ImGuiID > FocusScopeStack
ImGuiTextIndex DebugLogIndex
float NavWindowingHighlightAlpha
ImGuiNavItemData NavMoveResultLocal
ImGuiTextBuffer SettingsIniData
ImGuiDragDropFlags DragDropSourceFlags
ImVector< ImGuiTableTempData > TablesTempData
int FramerateSecPerFrameCount
ImVector< ImGuiContextHook > Hooks
ImGuiNavItemData NavMoveResultOther
ImGuiID CurrentFocusScopeId
ImU32 ActiveIdUsingNavDirMask
ImGuiWindow * HoveredWindow
ImVec2 NavWindowingAccumDeltaPos
ImDrawListSharedData DrawListSharedData
ImVec2 WheelingWindowWheelRemainder
ImGuiDragDropFlags DragDropAcceptFlags
ImGuiID HoverDelayIdPreviousFrame
ImVector< ImGuiGroupData > GroupStack
int WantCaptureMouseNextFrame
ImGuiNavItemData NavTabbingResultFirst
ImGuiTextBuffer LogBuffer
ImGuiID NavActivateId
ImGuiLogType LogType
ImVector< ImGuiShrinkWidthItem > ShrinkWidthBuffer
ImGuiID DragDropHoldJustPressedId
ImVector< ImGuiItemFlags > ItemFlagsStack
const char * LogNextSuffix
ImGuiID DebugItemPickerBreakId
ImGuiKeyOwnerData KeysOwnerData[ImGuiKey_NamedKey_COUNT]
ImVector< ImFont * > FontStack
ImPool< ImGuiTabBar > TabBars
ImGuiWindow * NavWindowingTarget
ImGuiID ActiveIdIsAlive
bool NavInitRequestFromMove
ImGuiDir NavMoveDirForDebug
ImGuiWindow * ActiveIdWindow
ImVector< ImGuiWindowStackData > CurrentWindowStack
ImRect DragDropTargetRect
ImGuiKeyRoutingTable KeysRoutingTable
bool ActiveIdHasBeenPressedBefore
bool ActiveIdIsJustActivated
ImVector< ImGuiViewportP * > Viewports
ImGuiWindow * CurrentWindow
ImVector< ImGuiListClipperData > ClipperTempData
ImVector< float > TablesLastTimeActive
ImGuiWindow * NavWindowingListWindow
bool ActiveIdPreviousFrameIsAlive
ImGuiWindow * NavWindowingTargetAnim
bool WithinFrameScopeWithImplicitWindow
ImVector< char > ClipboardHandlerData
ImVector< char > TempBuffer
ImGuiMouseCursor MouseCursor
ImGuiInputTextState InputTextState
ImGuiID DragDropAcceptIdPrev
ImVec2 NavWindowingAccumDeltaSize
ImVec2 MouseLastValidPos
ImVector< ImGuiStyleMod > StyleVarStack
ImGuiID NavNextActivateId
float FramerateSecPerFrameAccum
ImVector< ImDrawChannel > DrawChannelsTempMergeBuffer
ImGuiWindow * ActiveIdPreviousFrameWindow
unsigned char DragDropPayloadBufLocal[16]
ImGuiID NavFocusScopeId
float HoveredIdNotActiveTimer
ImU32 ActiveIdUsingNavInputMask
ImGuiWindow * HoveredWindowUnderMovingWindow
bool ActiveIdHasBeenEditedBefore
bool NavMoveForwardToNextFrame
ImGuiPlatformImeData PlatformImeDataPrev
ImChunkStream< ImGuiTableSettings > SettingsTables
float HoverDelayClearTimer
ImGuiKeyChord NavMoveKeyMods
ImGuiTable * CurrentTable
ImGuiStorage WindowsById
ImGuiKeyChord NavJustMovedToKeyMods
ImVector< ImGuiSettingsHandler > SettingsHandlers
ImRect NavScoringNoClipRect
ImGuiTabBar * CurrentTabBar
ImGuiWindow * NavWindow
ImGuiActivateFlags NavActivateFlags
ImVector< ImGuiColorMod > ColorStack
ImGuiNavItemData NavMoveResultLocalVisible
ImGuiNavMoveFlags NavMoveFlags
ImVector< ImGuiInputEvent > InputEventsQueue
short TooltipOverrideCount
bool ActiveIdHasBeenEditedThisFrame
ImVec2 WheelingWindowRefMousePos
ImVector< ImGuiInputEvent > InputEventsTrail
bool ActiveIdNoClearOnFocusLoss
ImGuiID NavJustMovedToFocusScopeId
ImGuiID DragDropAcceptIdCurr
ImVector< unsigned char > DragDropPayloadBufHeap
ImFileHandle LogFile
ImGuiID ActiveIdPreviousFrame
ImGuiID DragDropTargetId
ImPool< ImGuiTable > Tables
ImU8 DebugLogClipperAutoDisableFrames
void * GetVarPtr(void *parent) const
ImGuiDataType Type
float BackupCurrLineTextBaseOffset
ImGuiID BackupActiveIdIsAlive
bool BackupActiveIdPreviousFrameIsAlive
void(* SetPlatformImeDataFn)(ImGuiViewport *viewport, ImGuiPlatformImeData *data)
Definition imgui.h:1964
ImVec2 DisplaySize
Definition imgui.h:1913
IMGUI_API void AddFocusEvent(bool focused)
Definition imgui.cpp:1509
bool WantCaptureMouseUnlessPopupClose
Definition imgui.h:2042
IMGUI_API void AddInputCharacterUTF16(ImWchar16 c)
Definition imgui.cpp:1270
IMGUI_API ImGuiIO()
Definition imgui.cpp:1187
IMGUI_API void AddInputCharacter(unsigned int c)
Definition imgui.cpp:1254
bool WantTextInput
Definition imgui.h:1999
ImVec2 MousePosPrev
Definition imgui.h:2043
ImFont * FontDefault
Definition imgui.h:1930
float MouseDoubleClickMaxDist
Definition imgui.h:1919
void * ClipboardUserData
Definition imgui.h:1960
bool ConfigWindowsMoveFromTitleBarOnly
Definition imgui.h:1941
float HoverDelayShort
Definition imgui.h:1924
int MetricsRenderIndices
Definition imgui.h:2006
bool KeyAlt
Definition imgui.h:2036
void(* SetClipboardTextFn)(void *user_data, const char *text)
Definition imgui.h:1959
int MetricsActiveAllocations
Definition imgui.h:2009
float MouseWheel
Definition imgui.h:2032
ImVec2 MouseClickedPos[5]
Definition imgui.h:2044
ImFontAtlas * Fonts
Definition imgui.h:1927
float MouseWheelH
Definition imgui.h:2033
float KeyRepeatDelay
Definition imgui.h:1921
bool MouseReleased[5]
Definition imgui.h:2050
IMGUI_API void AddMouseWheelEvent(float wheel_x, float wheel_y)
Definition imgui.cpp:1492
bool KeyShift
Definition imgui.h:2035
bool WantCaptureKeyboard
Definition imgui.h:1998
ImWchar16 InputQueueSurrogate
Definition imgui.h:2061
ImVector< ImWchar > InputQueueCharacters
Definition imgui.h:2062
float DeltaTime
Definition imgui.h:1914
IMGUI_API void AddKeyEvent(ImGuiKey key, bool down)
Definition imgui.cpp:1406
bool KeyCtrl
Definition imgui.h:2034
const char * BackendPlatformName
Definition imgui.h:1950
float MouseDownDurationPrev[5]
Definition imgui.h:2054
bool KeysDown[ImGuiKey_COUNT]
Definition imgui.h:2017
ImVec2 MouseDelta
Definition imgui.h:2010
IMGUI_API void ClearInputKeys()
Definition imgui.cpp:1323
bool MouseDownOwnedUnlessPopupClose[5]
Definition imgui.h:2052
ImGuiConfigFlags ConfigFlags
Definition imgui.h:1911
bool MouseDownOwned[5]
Definition imgui.h:2051
bool WantSaveIniSettings
Definition imgui.h:2001
IMGUI_API void SetKeyEventNativeData(ImGuiKey key, int native_keycode, int native_scancode, int native_legacy_index=-1)
Definition imgui.cpp:1416
void * BackendPlatformUserData
Definition imgui.h:1952
ImGuiKeyData KeysData[ImGuiKey_KeysData_SIZE]
Definition imgui.h:2041
bool AppFocusLost
Definition imgui.h:2057
ImVec2 DisplayFramebufferScale
Definition imgui.h:1931
ImS8 BackendUsingLegacyKeyArrays
Definition imgui.h:2059
float FontGlobalScale
Definition imgui.h:1928
ImGuiKeyChord KeyMods
Definition imgui.h:2040
IMGUI_API void ClearInputCharacters()
Definition imgui.cpp:1317
bool MouseClicked[5]
Definition imgui.h:2046
float MouseDragMaxDistanceSqr[5]
Definition imgui.h:2055
bool WantSetMousePos
Definition imgui.h:2000
const char * IniFilename
Definition imgui.h:1916
void * ImeWindowHandle
Definition imgui.h:1966
bool MouseDoubleClicked[5]
Definition imgui.h:2047
void * UserData
Definition imgui.h:1925
float Framerate
Definition imgui.h:2004
IMGUI_API void SetAppAcceptingEvents(bool accepting_events)
Definition imgui.cpp:1439
int MetricsRenderVertices
Definition imgui.h:2005
bool ConfigDragClickToInputText
Definition imgui.h:1939
bool MouseDown[5]
Definition imgui.h:2031
ImGuiContext * Ctx
Definition imgui.h:2025
bool NavVisible
Definition imgui.h:2003
ImGuiBackendFlags BackendFlags
Definition imgui.h:1912
const char *(* GetClipboardTextFn)(void *user_data)
Definition imgui.h:1958
bool MouseDrawCursor
Definition imgui.h:1934
float IniSavingRate
Definition imgui.h:1915
void * BackendRendererUserData
Definition imgui.h:1953
IMGUI_API void AddMouseButtonEvent(int button, bool down)
Definition imgui.cpp:1469
int KeyMap[ImGuiKey_COUNT]
Definition imgui.h:2016
bool NavActive
Definition imgui.h:2002
bool BackendUsingLegacyNavInputArray
Definition imgui.h:2060
bool ConfigWindowsResizeFromEdges
Definition imgui.h:1940
bool AppAcceptingEvents
Definition imgui.h:2058
bool ConfigMacOSXBehaviors
Definition imgui.h:1935
float MouseDownDuration[5]
Definition imgui.h:2053
IMGUI_API void AddMousePosEvent(float x, float y)
Definition imgui.cpp:1445
bool ConfigInputTextEnterKeepActive
Definition imgui.h:1938
IMGUI_API void AddInputCharactersUTF8(const char *str)
Definition imgui.cpp:1304
ImU16 MouseClickedCount[5]
Definition imgui.h:2048
IMGUI_API void AddKeyAnalogEvent(ImGuiKey key, bool down, float v)
Definition imgui.cpp:1366
float KeyRepeatRate
Definition imgui.h:1922
const char * BackendRendererName
Definition imgui.h:1951
bool ConfigInputTextCursorBlink
Definition imgui.h:1937
ImVec2 MousePos
Definition imgui.h:2030
void * BackendLanguageUserData
Definition imgui.h:1954
float MouseDragThreshold
Definition imgui.h:1920
float PenPressure
Definition imgui.h:2056
float HoverDelayNormal
Definition imgui.h:1923
int MetricsActiveWindows
Definition imgui.h:2008
const char * LogFilename
Definition imgui.h:1917
int MetricsRenderWindows
Definition imgui.h:2007
float ConfigMemoryCompactTimer
Definition imgui.h:1942
float MouseDoubleClickTime
Definition imgui.h:1918
ImU16 MouseClickedLastCount[5]
Definition imgui.h:2049
bool ConfigInputTrickleEventQueue
Definition imgui.h:1936
bool WantCaptureMouse
Definition imgui.h:1997
bool FontAllowUserScaling
Definition imgui.h:1929
double MouseClickedTime[5]
Definition imgui.h:2045
bool KeySuper
Definition imgui.h:2037
ImGuiInputEventType Type
ImGuiInputEventAppFocused AppFocused
ImGuiInputEventKey Key
ImGuiInputEventMouseButton MouseButton
ImGuiInputSource Source
ImGuiInputEventMouseWheel MouseWheel
ImGuiInputEventMousePos MousePos
ImGuiInputEventText Text
bool Down
Definition imgui.h:1899
float DownDurationPrev
Definition imgui.h:1901
float DownDuration
Definition imgui.h:1900
float AnalogValue
Definition imgui.h:1902
ImGuiKeyRoutingIndex NextEntryIndex
ImVector< ImGuiKeyRoutingData > Entries
ImVector< ImGuiKeyRoutingData > EntriesNext
ImGuiKeyRoutingIndex Index[ImGuiKey_NamedKey_COUNT]
ImGuiItemStatusFlags StatusFlags
ImGuiItemFlags InFlags
void Reset(ImGuiListClipper *clipper)
ImVector< ImGuiListClipperRange > Ranges
IMGUI_API void End()
Definition imgui.cpp:2756
ImGuiContext * Ctx
Definition imgui.h:2307
void * TempData
Definition imgui.h:2313
IMGUI_API void ForceDisplayRangeByIndices(int item_min, int item_max)
Definition imgui.cpp:2779
IMGUI_API void Begin(int items_count, float items_height=-1.0f)
Definition imgui.cpp:2731
IMGUI_API bool Step()
Definition imgui.cpp:2911
IMGUI_API ~ImGuiListClipper()
Definition imgui.cpp:2726
IMGUI_API ImGuiListClipper()
Definition imgui.cpp:2718
static ImGuiListClipperRange FromPositions(float y1, float y2, int off_min, int off_max)
static ImGuiListClipperRange FromIndices(int min, int max)
const char * Text
ImGuiLocKey Key
void Update(float spacing, bool window_reappearing)
ImGuiItemFlags InFlags
ImGuiWindow * Window
ImGuiNextItemDataFlags Flags
ImGuiNextWindowDataFlags Flags
ImGuiSizeCallback SizeCallback
ImGuiOldColumnFlags Flags
ImVector< ImGuiOldColumnData > Columns
ImGuiID SourceParentId
Definition imgui.h:2129
bool Preview
Definition imgui.h:2132
bool Delivery
Definition imgui.h:2133
int DataSize
Definition imgui.h:2125
char DataType[32+1]
Definition imgui.h:2131
bool IsDataType(const char *type) const
Definition imgui.h:2137
void Clear()
Definition imgui.h:2136
ImGuiID SourceId
Definition imgui.h:2128
int DataFrameCount
Definition imgui.h:2130
void * Data
Definition imgui.h:2124
ImGuiWindow * Window
ImGuiWindow * BackupNavWindow
void(* ReadLineFn)(ImGuiContext *ctx, ImGuiSettingsHandler *handler, void *entry, const char *line)
void(* ClearAllFn)(ImGuiContext *ctx, ImGuiSettingsHandler *handler)
void *(* ReadOpenFn)(ImGuiContext *ctx, ImGuiSettingsHandler *handler, const char *name)
void(* ApplyAllFn)(ImGuiContext *ctx, ImGuiSettingsHandler *handler)
void(* WriteAllFn)(ImGuiContext *ctx, ImGuiSettingsHandler *handler, ImGuiTextBuffer *out_buf)
void SetToContextState(ImGuiContext *ctx)
Definition imgui.cpp:9102
void CompareWithContextState(ImGuiContext *ctx)
Definition imgui.cpp:9118
float CopyToClipboardLastTime
ImVector< ImGuiStackLevelInfo > Results
IMGUI_API float GetFloat(ImGuiID key, float default_val=0.0f) const
Definition imgui.cpp:2325
IMGUI_API bool GetBool(ImGuiID key, bool default_val=false) const
Definition imgui.cpp:2320
IMGUI_API int * GetIntRef(ImGuiID key, int default_val=0)
Definition imgui.cpp:2342
IMGUI_API void ** GetVoidPtrRef(ImGuiID key, void *default_val=NULL)
Definition imgui.cpp:2363
IMGUI_API float * GetFloatRef(ImGuiID key, float default_val=0.0f)
Definition imgui.cpp:2355
IMGUI_API void SetVoidPtr(ImGuiID key, void *val)
Definition imgui.cpp:2399
IMGUI_API void BuildSortByKey()
Definition imgui.cpp:2297
ImVector< ImGuiStoragePair > Data
Definition imgui.h:2254
void Clear()
Definition imgui.h:2259
IMGUI_API void * GetVoidPtr(ImGuiID key) const
Definition imgui.cpp:2333
IMGUI_API void SetFloat(ImGuiID key, float val)
Definition imgui.cpp:2388
IMGUI_API void SetBool(ImGuiID key, bool val)
Definition imgui.cpp:2383
IMGUI_API int GetInt(ImGuiID key, int default_val=0) const
Definition imgui.cpp:2312
IMGUI_API void SetAllInt(int val)
Definition imgui.cpp:2410
IMGUI_API bool * GetBoolRef(ImGuiID key, bool default_val=false)
Definition imgui.cpp:2350
IMGUI_API void SetInt(ImGuiID key, int val)
Definition imgui.cpp:2372
float ScrollbarRounding
Definition imgui.h:1861
bool AntiAliasedLines
Definition imgui.h:1877
float GrabMinSize
Definition imgui.h:1862
ImVec2 WindowMinSize
Definition imgui.h:1844
float FrameRounding
Definition imgui.h:1852
ImVec2 ButtonTextAlign
Definition imgui.h:1869
ImVec2 ItemInnerSpacing
Definition imgui.h:1855
bool AntiAliasedFill
Definition imgui.h:1879
float FrameBorderSize
Definition imgui.h:1853
float TabRounding
Definition imgui.h:1865
float TabBorderSize
Definition imgui.h:1866
ImVec4 Colors[ImGuiCol_COUNT]
Definition imgui.h:1882
float IndentSpacing
Definition imgui.h:1858
ImVec2 WindowPadding
Definition imgui.h:1841
ImVec2 WindowTitleAlign
Definition imgui.h:1845
float CurveTessellationTol
Definition imgui.h:1880
float GrabRounding
Definition imgui.h:1863
float PopupRounding
Definition imgui.h:1849
float WindowBorderSize
Definition imgui.h:1843
float ChildBorderSize
Definition imgui.h:1848
float MouseCursorScale
Definition imgui.h:1876
ImGuiDir ColorButtonPosition
Definition imgui.h:1868
ImVec2 ItemSpacing
Definition imgui.h:1854
float LogSliderDeadzone
Definition imgui.h:1864
IMGUI_API void ScaleAllSizes(float scale_factor)
Definition imgui.cpp:1159
float SeparatorTextBorderSize
Definition imgui.h:1871
ImVec2 DisplaySafeAreaPadding
Definition imgui.h:1875
float ColumnsMinSpacing
Definition imgui.h:1859
float ScrollbarSize
Definition imgui.h:1860
float Alpha
Definition imgui.h:1839
ImVec2 CellPadding
Definition imgui.h:1856
ImVec2 DisplayWindowPadding
Definition imgui.h:1874
IMGUI_API ImGuiStyle()
Definition imgui.cpp:1107
ImVec2 SeparatorTextAlign
Definition imgui.h:1872
ImVec2 TouchExtraPadding
Definition imgui.h:1857
ImGuiDir WindowMenuButtonPosition
Definition imgui.h:1846
float ChildRounding
Definition imgui.h:1847
float PopupBorderSize
Definition imgui.h:1850
float DisabledAlpha
Definition imgui.h:1840
float CircleTessellationMaxError
Definition imgui.h:1881
bool AntiAliasedLinesUseTex
Definition imgui.h:1878
float WindowRounding
Definition imgui.h:1842
float TabMinWidthForCloseButton
Definition imgui.h:1867
ImVec2 SeparatorTextPadding
Definition imgui.h:1873
ImVec2 SelectableTextAlign
Definition imgui.h:1870
ImVec2 FramePadding
Definition imgui.h:1851
ImGuiStyleVar VarIdx
float BackupFloat[2]
float ScrollingRectMaxX
ImGuiID SelectedTabId
ImVector< ImGuiTabItem > Tabs
float ScrollingRectMinX
ImGuiTableColumnIdx HoveredColumnBody
ImRect HostClipRect
ImRect InnerClipRect
ImSpan< ImGuiTableColumn > Columns
ImS16 InstanceCurrent
ImGuiWindow * OuterWindow
ImGuiWindow * InnerWindow
IMGUI_API void appendf(const char *fmt,...) IM_FMTARGS(2)
Definition imgui.cpp:2549
int size() const
Definition imgui.h:2224
void reserve(int capacity)
Definition imgui.h:2227
static IMGUI_API char EmptyString[1]
Definition imgui.h:2529
IMGUI_API void append(const char *str, const char *str_end=NULL)
Definition imgui.cpp:2531
void clear()
Definition imgui.h:2226
ImVector< char > Buf
Definition imgui.h:2217
const char * c_str() const
Definition imgui.h:2228
IMGUI_API void appendfv(const char *fmt, va_list args) IM_FMTLIST(2)
Definition imgui.cpp:2558
const char * begin() const
Definition imgui.h:2222
bool empty() const
Definition imgui.h:2225
IMGUI_API void split(char separator, ImVector< ImGuiTextRange > *out) const
Definition imgui.cpp:2442
IMGUI_API ImGuiTextFilter(const char *default_filter="")
Definition imgui.cpp:2421
ImVector< ImGuiTextRange > Filters
Definition imgui.h:2209
IMGUI_API bool PassFilter(const char *text, const char *text_end=NULL) const
Definition imgui.cpp:2481
IMGUI_API bool Draw(const char *label="Filter (inc,-exc)", float width=0.0f)
Definition imgui.cpp:2432
char InputBuf[256]
Definition imgui.h:2208
IMGUI_API void Build()
Definition imgui.cpp:2460
const char * get_line_end(const char *base, int n)
void append(const char *base, int old_size, int new_size)
Definition imgui.cpp:2584
const char * get_line_begin(const char *base, int n)
ImGuiViewportFlags Flags
Definition imgui.h:2959
ImVec2 Pos
Definition imgui.h:2960
void * PlatformHandleRaw
Definition imgui.h:2966
ImVec2 Size
Definition imgui.h:2961
ImVec2 WorkSize
Definition imgui.h:2963
ImVec2 GetCenter() const
Definition imgui.h:2971
ImDrawDataBuilder DrawDataBuilder
ImDrawList * DrawLists[2]
ImDrawData DrawDataP
ImRect GetMainRect() const
ImRect GetWorkRect() const
ImVec2 ScrollbarSizes
ImRect TitleBarRect() const
ImGuiContext * Ctx
ImGuiCond SetWindowSizeAllowFlags
int MemoryDrawListVtxCapacity
ImRect Rect() const
short BeginCountPreviousFrame
ImVector< ImGuiID > IDStack
ImGuiID NavLastIds[ImGuiNavLayer_COUNT]
ImGuiStorage StateStorage
signed char ResizeBorderHeld
ImDrawList * DrawList
ImVec2 ScrollTargetCenterRatio
ImGuiID GetIDFromRectangle(const ImRect &r_abs)
Definition imgui.cpp:3700
ImGuiCond SetWindowCollapsedAllowFlags
ImVec2 SetWindowPosPivot
ImRect MenuBarRect() const
ImGuiWindow * RootWindowPopupTree
ImGuiID NavRootFocusScopeId
ImGuiWindow * ParentWindow
ImS8 HiddenFramesForRenderOnly
ImVec2ih HitTestHoleOffset
ImGuiID GetID(const char *str, const char *str_end=NULL)
Definition imgui.cpp:3669
float CalcFontSize() const
ImVec2 SetWindowPosVal
ImGuiWindow * NavLastChildNavWindow
ImS8 HiddenFramesCannotSkipItems
ImGuiWindowTempData DC
ImGuiWindowFlags Flags
ImGuiCond SetWindowPosAllowFlags
ImGuiWindow * RootWindowForNav
int MemoryDrawListIdxCapacity
ImGuiWindow * ParentWindowInBeginStack
ImVec2 ScrollTargetEdgeSnapDist
short BeginOrderWithinParent
ImGuiDir AutoPosLastDirection
ImVec2 ContentSizeExplicit
ImDrawList DrawListInst
ImVec2ih HitTestHoleSize
ImVec2 ContentSizeIdeal
ImRect NavRectRel[ImGuiNavLayer_COUNT]
ImGuiViewportP * Viewport
ImRect OuterRectClipped
ImGuiWindow(ImGuiContext *context, const char *name)
Definition imgui.cpp:3638
float MenuBarHeight() const
float TitleBarHeight() const
ImVector< ImGuiOldColumns > ColumnsStorage
ImRect ParentWorkRect
ImGuiWindow * RootWindowForTitleBarHighlight
ImRect ContentRegionRect
ImGuiWindow * RootWindow
ImS8 HiddenFramesCanSkipItems
short BeginOrderWithinContext
ImGuiLastItemData ParentLastItemDataBackup
ImGuiStackSizes StackSizesOnBegin
ImGuiLayoutType LayoutType
ImGuiMenuColumns MenuColumns
ImGuiNavLayer NavLayerCurrent
ImVector< float > TextWrapPosStack
ImVector< float > ItemWidthStack
ImVector< ImGuiWindow * > ChildWindows
ImGuiOldColumns * CurrentColumns
ImGuiStorage * StateStorage
ImGuiLayoutType ParentLayoutType
T * GetByIndex(ImPoolIdx n)
int GetAliveCount() const
T * TryGetMapData(ImPoolIdx n)
int GetMapSize() const
void Clear()
bool Overlaps(const ImRect &r) const
bool IsInverted() const
void TranslateX(float dx)
ImVec4 ToVec4() const
void ClipWithFull(const ImRect &r)
ImVec2 GetBL() const
void Add(const ImVec2 &p)
float GetHeight() const
void Translate(const ImVec2 &d)
ImVec2 Max
void TranslateY(float dy)
void ClipWith(const ImRect &r)
bool Contains(const ImVec2 &p) const
ImVec2 GetBR() const
ImVec2 GetSize() const
void Expand(const float amount)
ImVec2 Min
float GetWidth() const
float y
Definition imgui.h:255
float x
Definition imgui.h:255
float x
Definition imgui.h:268
float y
Definition imgui.h:268
float z
Definition imgui.h:268
float w
Definition imgui.h:268
void reserve(int new_capacity)
Definition imgui.h:1809
void push_front(const T &v)
Definition imgui.h:1815
T & back()
Definition imgui.h:1801
bool contains(const T &v) const
Definition imgui.h:1820
T * erase(const T *it)
Definition imgui.h:1816
void pop_back()
Definition imgui.h:1814
int index_from_ptr(const T *it) const
Definition imgui.h:1825
T * find(const T &v)
Definition imgui.h:1821
bool empty() const
Definition imgui.h:1787
void push_back(const T &v)
Definition imgui.h:1813
T * begin()
Definition imgui.h:1795
int Size
Definition imgui.h:1768
int Capacity
Definition imgui.h:1769
T * Data
Definition imgui.h:1770
void clear_destruct()
Definition imgui.h:1785
void resize(int new_size)
Definition imgui.h:1806
void clear()
Definition imgui.h:1783
void clear_delete()
Definition imgui.h:1784
void swap(ImVector< T > &rhs)
Definition imgui.h:1803